@fiscozen/input 0.1.17 → 1.0.0-next.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.
@@ -1,111 +1,253 @@
1
- import { IconVariant } from '@fiscozen/icons';
1
+ import { IconButtonVariant } from '@fiscozen/button';
2
+ import { IconSize, IconVariant } from '@fiscozen/icons';
2
3
 
4
+ export type InputEnvironment = "backoffice" | "frontoffice";
3
5
  type FzInputProps = {
4
6
  /**
5
- * The label displayed on top of the input
7
+ * Text label displayed above the input field. Overridden by label slot if provided.
6
8
  */
7
- label: string;
9
+ label?: string;
8
10
  /**
9
- * The size of the input
11
+ * Environment determining input size and styling
12
+ * @default 'frontoffice'
13
+ */
14
+ environment?: InputEnvironment;
15
+ /**
16
+ * Visual size affecting height, padding, and text size
17
+ *
18
+ * @deprecated Use the 'environment' prop instead. This prop will be removed in a future version.
19
+ * Size values map to environments: sm/md → backoffice, lg → frontoffice
10
20
  */
11
21
  size?: "sm" | "md" | "lg";
12
22
  /**
13
- * The placeholder displayed in the input
23
+ * Placeholder text shown when input is empty. Behavior differs based on variant.
14
24
  */
15
25
  placeholder?: string;
16
26
  /**
17
- * If set to true, the input is required
27
+ * Marks input as required. Adds asterisk to label and sets native required attribute.
28
+ * @default false
18
29
  */
19
30
  required?: boolean;
20
31
  /**
21
- * If set to true, the input is disabled
32
+ * Disables input interaction and applies disabled styling
33
+ * @default false
22
34
  */
23
35
  disabled?: boolean;
24
36
  /**
25
- * If set to true, the input is in error state
37
+ * Shows error state with red border and enables errorMessage slot display
38
+ * @default false
26
39
  */
27
40
  error?: boolean;
28
41
  /**
29
- * Left icon name
42
+ * Font Awesome icon name displayed on the left side of input
30
43
  */
31
44
  leftIcon?: string;
32
45
  /**
33
- * Left icon variant
46
+ * Visual style variant for left icon (solid, regular, light, etc.)
34
47
  */
35
48
  leftIconVariant?: IconVariant;
36
49
  /**
37
- * Right icon name
50
+ * Button variant for left icon when rendered as clickable button
51
+ */
52
+ leftIconButtonVariant?: IconButtonVariant;
53
+ /**
54
+ * Accessible label for left icon when clickable. Required for screen reader accessibility.
55
+ */
56
+ leftIconAriaLabel?: string;
57
+ /**
58
+ * Font Awesome icon name displayed on the right side of input
38
59
  */
39
60
  rightIcon?: string;
40
61
  /**
41
- * Right icon variant
62
+ * Additional CSS classes applied to right icon container
63
+ */
64
+ rightIconClass?: string;
65
+ /**
66
+ * Size override for right icon. If not provided, uses input size mapping.
67
+ * @deprecated This prop is deprecated and will be removed in a future version.
68
+ * Icons now have a fixed size of "md". This prop will be ignored.
69
+ */
70
+ rightIconSize?: IconSize;
71
+ /**
72
+ * Visual style variant for right icon (solid, regular, light, etc.)
42
73
  */
43
74
  rightIconVariant?: IconVariant;
44
75
  /**
45
- * The input type
76
+ * Renders right icon as clickable button instead of static icon
77
+ * @default false
78
+ */
79
+ rightIconButton?: boolean;
80
+ /**
81
+ * Button variant for right icon when rightIconButton is true
82
+ * @default 'invisible'
83
+ */
84
+ rightIconButtonVariant?: IconButtonVariant;
85
+ /**
86
+ * Accessible label for right icon when clickable. Required for screen reader accessibility.
87
+ */
88
+ rightIconAriaLabel?: string;
89
+ /**
90
+ * Font Awesome icon name displayed as second icon on the right side of input.
91
+ * Priority order: secondRightIcon > rightIcon > valid
92
+ */
93
+ secondRightIcon?: string;
94
+ /**
95
+ * Additional CSS classes applied to second right icon container
96
+ */
97
+ secondRightIconClass?: string;
98
+ /**
99
+ * Visual style variant for second right icon (solid, regular, light, etc.)
100
+ */
101
+ secondRightIconVariant?: IconVariant;
102
+ /**
103
+ * Renders second right icon as clickable button instead of static icon
104
+ * @default false
105
+ */
106
+ secondRightIconButton?: boolean;
107
+ /**
108
+ * Button variant for second right icon when secondRightIconButton is true
109
+ * @default 'invisible'
110
+ */
111
+ secondRightIconButtonVariant?: IconButtonVariant;
112
+ /**
113
+ * Accessible label for second right icon when clickable. Required for screen reader accessibility.
114
+ */
115
+ secondRightIconAriaLabel?: string;
116
+ /**
117
+ * Native HTML input type. Determines keyboard layout and validation behavior
118
+ * @default 'text'
46
119
  */
47
120
  type?: "text" | "password" | "email" | "number" | "tel" | "url";
48
121
  /**
49
- * If set to true, the input is valid
122
+ * Shows success checkmark icon on the right when true. Takes precedence over rightIcon
123
+ * @default false
50
124
  */
51
125
  valid?: boolean;
52
126
  /**
53
- * Pattern to validate the input
127
+ * Visual presentation style. 'floating-label' moves placeholder above input when focused/filled
128
+ * @default 'normal'
129
+ */
130
+ variant?: 'normal' | 'floating-label';
131
+ /**
132
+ * HTML5 pattern attribute for native browser validation
54
133
  */
55
134
  pattern?: string;
56
135
  /**
57
- * Defines the textarea key in a form
136
+ * Native name attribute for form submission and identification
58
137
  */
59
138
  name?: string;
60
139
  /**
61
- * native readonly input value
140
+ * Native readonly attribute. Prevents user input while keeping field focusable
141
+ * @default false
62
142
  */
63
143
  readonly?: boolean;
64
144
  /**
65
- * native maxlength input value
145
+ * Native maxlength attribute. Limits maximum number of characters
66
146
  */
67
147
  maxlength?: number;
68
148
  /**
69
- * right icon class
149
+ * Native autocomplete attribute. Controls browser autocomplete and suggestions.
150
+ * When false, sets autocomplete="off" to disable browser autocomplete.
151
+ * @default false
70
152
  */
71
- rightIconClass?: string;
153
+ autocomplete?: boolean;
72
154
  /**
73
- * left icon class
155
+ * Additional CSS classes applied to left icon container
74
156
  */
75
157
  leftIconClass?: string;
76
158
  };
77
- interface FzCurrencyInputProps extends Omit<FzInputProps, "type" | "modelValue"> {
78
- /**
79
- * Is set to true, an empty string will be casted to null
159
+ interface FzCurrencyInputProps extends Omit<FzInputProps, "type" | "modelValue" | "rightIcon" | "rightIconSize" | "rightIconVariant" | "rightIconButton" | "rightIconButtonVariant" | "rightIconAriaLabel" | "rightIconClass" | "secondRightIcon" | "secondRightIconClass" | "secondRightIconVariant" | "secondRightIconButton" | "secondRightIconButtonVariant" | "secondRightIconAriaLabel"> {
160
+ /**
161
+ * The v-model value.
162
+ *
163
+ * **Type assertion**: This prop accepts `number | string | undefined | null` as input,
164
+ * but the component **always emits** `number | undefined | null` (never `string`).
165
+ * Strings are automatically parsed (Italian format: "1.234,56" → 1234.56) and converted
166
+ * to numbers internally.
167
+ *
168
+ * **nullOnEmpty**: When `nullOnEmpty` is `true`, empty input emits `null` instead of `undefined`.
169
+ *
170
+ * **Deprecation**: String values are deprecated and will be removed in a future version.
171
+ * A console warning is shown when strings are used. Please use `number | undefined | null` instead
172
+ * for type safety and future compatibility.
173
+ *
174
+ * @example
175
+ * ```vue
176
+ * <!-- ✅ Recommended: number | undefined | null -->
177
+ * <script setup>
178
+ * const amount = ref<number | undefined>(undefined);
179
+ * </script>
180
+ * <template>
181
+ * <FzCurrencyInput v-model="amount" />
182
+ * </template>
183
+ *
184
+ * <!-- ✅ With nullOnEmpty: number | null -->
185
+ * <script setup>
186
+ * const amount = ref<number | null>(null);
187
+ * </script>
188
+ * <template>
189
+ * <FzCurrencyInput v-model="amount" :nullOnEmpty="true" />
190
+ * </template>
191
+ *
192
+ * <!-- ⚠️ Deprecated: string (still works but shows warning) -->
193
+ * <script setup>
194
+ * const amount = ref<string>("1234,56");
195
+ * </script>
196
+ * <template>
197
+ * <FzCurrencyInput v-model="amount" />
198
+ * </template>
199
+ * ```
200
+ */
201
+ modelValue?: number | string | undefined | null;
202
+ /**
203
+ * Converts empty input to null instead of undefined.
204
+ * When true, empty input (v-model undefined) will emit null instead of undefined.
205
+ * @default false
80
206
  */
81
207
  nullOnEmpty?: boolean;
82
208
  /**
83
- * Minimum number of decimal places allowed, set null to allow arbitrary decimal values length
84
- * note that limits from Intl.NumberFormat still apply
85
- * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#digit_options
209
+ * Converts empty input to 0 instead of undefined.
210
+ * When true, empty input (v-model undefined) will emit 0 instead of undefined.
211
+ * @default false
212
+ */
213
+ zeroOnEmpty?: boolean;
214
+ /**
215
+ * Minimum decimal places in formatted output
216
+ * @default 2
217
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#digit_options
86
218
  */
87
219
  minimumFractionDigits?: number;
88
220
  /**
89
- * Maximum number of decimal places allowed, set null to allow arbitrary decimal values length
90
- * note that limits from Intl.NumberFormat still apply
91
- * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#digit_options
221
+ * Maximum decimal places in formatted output
222
+ * @default 2
223
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#digit_options
92
224
  */
93
225
  maximumFractionDigits?: number;
94
226
  /**
95
- * Minimum number value
227
+ * Minimum allowed value. Values below this are clamped to min
96
228
  */
97
229
  min?: number;
98
230
  /**
99
- * Maximum number value
231
+ * Maximum allowed value. Values above this are clamped to max
100
232
  */
101
233
  max?: number;
102
234
  /**
103
- * Quantized step
235
+ * Step increment for arrow buttons. When forceStep is true, values are rounded to nearest step multiple
236
+ * @default 1
104
237
  */
105
238
  step?: number;
106
239
  /**
107
- * Allow only mutiples of step
240
+ * Enforces quantization: values are automatically rounded to nearest step multiple
241
+ * @default false
108
242
  */
109
243
  forceStep?: boolean;
244
+ /**
245
+ * Custom accessible label for step up button. If not provided, uses default label.
246
+ */
247
+ stepUpAriaLabel?: string;
248
+ /**
249
+ * Custom accessible label for step down button. If not provided, uses default label.
250
+ */
251
+ stepDownAriaLabel?: string;
110
252
  }
111
253
  export { FzInputProps, FzCurrencyInputProps };
@@ -1,12 +1,27 @@
1
- import { Ref } from 'vue';
2
- import { FzInputProps } from './types';
1
+ import { ToRefs, Ref, ComputedRef } from 'vue';
2
+ import { FzInputProps, InputEnvironment } from './types';
3
3
 
4
- export default function useInputStyle(props: FzInputProps, container: Ref<HTMLElement | null>): {
4
+ /**
5
+ * Composable for managing FzInput component styles and computed classes
6
+ *
7
+ * Handles dynamic styling based on props, environment, variant, and state.
8
+ * Returns computed classes for container, label, input, help text, and error messages.
9
+ *
10
+ * @param props - Reactive props from FzInput component
11
+ * @param container - Reference to container DOM element
12
+ * @param model - Reactive model value (string | undefined)
13
+ * @param effectiveEnvironment - Computed effective environment (backoffice | frontoffice)
14
+ * @param isFocused - Reactive flag indicating if input is focused
15
+ * @returns Object containing computed classes and style-related properties
16
+ */
17
+ export default function useInputStyle(props: ToRefs<FzInputProps>, container: Ref<HTMLElement | null>, model: Ref<string | undefined>, effectiveEnvironment: ComputedRef<InputEnvironment>, isFocused: Ref<boolean>): {
5
18
  staticContainerClass: string;
6
- computedContainerClass: import('vue').ComputedRef<string[]>;
7
- computedLabelClass: import('vue').ComputedRef<string[]>;
19
+ computedContainerClass: ComputedRef<(string | undefined)[]>;
20
+ computedLabelClass: ComputedRef<string[]>;
8
21
  staticInputClass: string;
9
- computedHelpClass: import('vue').ComputedRef<string[]>;
10
- computedErrorClass: import('vue').ComputedRef<string[]>;
11
- containerWidth: import('vue').ComputedRef<string>;
22
+ computedInputClass: ComputedRef<string[]>;
23
+ computedHelpClass: ComputedRef<string[]>;
24
+ computedErrorClass: ComputedRef<string[]>;
25
+ containerWidth: ComputedRef<string>;
26
+ showNormalPlaceholder: ComputedRef<boolean>;
12
27
  };
@@ -0,0 +1,21 @@
1
+ import { InputEnvironment } from './types';
2
+
3
+ type InputSize = "sm" | "md" | "lg";
4
+ /**
5
+ * Maps deprecated InputSize to InputEnvironment
6
+ *
7
+ * Used for backward compatibility when size prop is provided instead of environment.
8
+ * Size values map to environments: sm/md → backoffice, lg → frontoffice
9
+ */
10
+ export declare const sizeToEnvironmentMapping: Record<InputSize, InputEnvironment>;
11
+ /**
12
+ * Generates a unique ID for input components.
13
+ *
14
+ * @returns Unique input ID with "fz-input" prefix
15
+ *
16
+ * @example
17
+ * generateInputId() // "fz-input-97123456-a8d3k"
18
+ * generateInputId() // "fz-input-97123457-k2m9p"
19
+ */
20
+ export declare function generateInputId(): string;
21
+ export {};
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ .fz-icon-button-wrapper[data-v-b4be112d]>button{gap:0!important;min-width:0!important}.fz-icon-button-wrapper--backoffice[data-v-b4be112d]>button{padding-left:5px;padding-right:5px}.fz-icon-button-wrapper--frontoffice[data-v-b4be112d]>button{padding-left:11px;padding-right:11px}.fz-container[data-v-8c40daeb]{display:flex}.fz-container--vertical[data-v-8c40daeb]{flex-direction:column}.fz-container--horizontal[data-v-8c40daeb]{flex-direction:row;flex-wrap:nowrap}.fz-container.align-items-start[data-v-8c40daeb]{align-items:flex-start}.fz-container.align-items-center[data-v-8c40daeb]{align-items:center}.fz-container.align-items-end[data-v-8c40daeb]{align-items:flex-end}.fz-container.align-items-stretch[data-v-8c40daeb]{align-items:stretch}.fz-container.align-items-baseline[data-v-8c40daeb]{align-items:baseline}.fz-container--horizontal.layout-expand-first[data-v-8c40daeb]>*:first-child{flex-grow:1}.fz-container--horizontal.layout-expand-all[data-v-8c40daeb]>*{flex-grow:1}.fz-container--horizontal.layout-space-between[data-v-8c40daeb]{justify-content:space-between}.fz-container--horizontal.layout-expand-last[data-v-8c40daeb]>*:last-child{flex-grow:1}.fz-container--vertical.gap-main-content-sm[data-v-8c40daeb]>p+p{margin-top:calc((0px - var(--main-content-sm, 32px)) + var(--paragraph-gap, 8px))}.fz-container--vertical.gap-main-content-base[data-v-8c40daeb]>p+p{margin-top:calc((0px - var(--main-content-base, 48px)) + var(--paragraph-gap, 8px))}.fz-container--vertical.gap-main-content-lg[data-v-8c40daeb]>p+p{margin-top:calc((0px - var(--main-content-lg, 64px)) + var(--paragraph-gap, 8px))}.fz-container--vertical.gap-section-content-none[data-v-8c40daeb]>p+p{margin-top:calc((0px - var(--section-content-none, 0px)) + var(--paragraph-gap, 8px))}.fz-container--vertical.gap-section-content-xs[data-v-8c40daeb]>p+p{margin-top:calc((0px - var(--section-content-xs, 8px)) + var(--paragraph-gap, 8px))}.fz-container--vertical.gap-section-content-sm[data-v-8c40daeb]>p+p{margin-top:calc((0px - var(--section-content-sm, 16px)) + var(--paragraph-gap, 8px))}.fz-container--vertical.gap-section-content-base[data-v-8c40daeb]>p+p{margin-top:calc((0px - var(--section-content-base, 24px)) + var(--paragraph-gap, 8px))}.fz-container--vertical.gap-section-content-lg[data-v-8c40daeb]>p+p{margin-top:calc((0px - var(--section-content-lg, 32px)) + var(--paragraph-gap, 8px))}.fz-container--horizontal[data-v-8c40daeb]>p+p{margin-top:0}.fz-button-group[data-v-79dd8b6f]>*:nth-child(1):nth-last-child(2),.fz-button-group[data-v-79dd8b6f]>*:nth-child(1):nth-last-child(2)~*{flex-basis:50%;flex-grow:0;flex-shrink:1}.fz-button-group[data-v-79dd8b6f]>*:nth-child(1):nth-last-child(3),.fz-button-group[data-v-79dd8b6f]>*:nth-child(1):nth-last-child(3)~*{flex-basis:33.333%;flex-grow:0;flex-shrink:1}.fz-button-group[data-v-79dd8b6f]>.fz-icon-button-wrapper{flex-basis:initial!important;flex-grow:0!important;flex-shrink:0!important}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiscozen/input",
3
- "version": "0.1.17",
3
+ "version": "1.0.0-next.1",
4
4
  "description": "Design System Input component",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
@@ -9,9 +9,9 @@
9
9
  "peerDependencies": {
10
10
  "tailwindcss": "^3.4.1",
11
11
  "vue": "^3.4.13",
12
- "@fiscozen/composables": "^0.1.36",
13
- "@fiscozen/icons": "^0.1.28",
14
- "@fiscozen/button": "^0.1.13"
12
+ "@fiscozen/icons": "^0.1.36",
13
+ "@fiscozen/composables": "^1.0.0",
14
+ "@fiscozen/button": "^1.0.1-next.1"
15
15
  },
16
16
  "devDependencies": {
17
17
  "@rushstack/eslint-patch": "^1.3.3",