jattac.libs.web.zest-textbox 0.2.0 → 0.2.2

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/dist/index.d.ts CHANGED
@@ -1 +1,155 @@
1
- export { default } from './ZestTextbox';
1
+ import React, { ReactNode } from 'react';
2
+
3
+ type ZestTextboxSize = "sm" | "md" | "lg";
4
+ type ZestConfigValue<T> = T | (() => T) | (() => Promise<T>);
5
+ type InputParser<T> = (value: string) => T | undefined;
6
+ type InputValidator<T> = (value: T | undefined) => boolean | string;
7
+ interface HelperTextConfig {
8
+ /**
9
+ * A function to process the raw input value into a new string.
10
+ * Ideal for formatting operations like currency conversion or sanitization.
11
+ * @param value The raw string value from the textbox.
12
+ * @returns The processed string to be used by the templater or for default rendering.
13
+ */
14
+ formatter?: (value: string) => string;
15
+ /**
16
+ * An optional function for advanced rendering of the helper text.
17
+ * It receives the processed string (from `formatter` or the raw value if no formatter is provided)
18
+ * and should return a ReactNode. If not provided, the processed string
19
+ * is rendered with default muted styling.
20
+ * @param formattedValue The processed string.
21
+ * @returns The ReactNode to be rendered as helper text.
22
+ */
23
+ templater?: (formattedValue: string) => React.ReactNode;
24
+ /**
25
+ * An optional CSS class to apply to the helper text container for custom styling.
26
+ */
27
+ className?: string;
28
+ }
29
+ interface ZestProps {
30
+ /**
31
+ * An object to configure the dynamic helper text displayed below the input.
32
+ * @see HelperTextConfig
33
+ */
34
+ helperTextConfig?: ZestConfigValue<HelperTextConfig>;
35
+ /**
36
+ * A callback that provides the parsed and validated value of the input on every valid change.
37
+ * This is a convenience prop to avoid using `event.target.value` and manual parsing/validation.
38
+ * @param value The current parsed and validated value of the input, or `undefined` if parsing failed.
39
+ */
40
+ onTextChanged?: (value: any | undefined) => void;
41
+ /**
42
+ * Sets the size of the textbox, affecting padding and font size.
43
+ * @default 'md'
44
+ */
45
+ zSize?: ZestConfigValue<ZestTextboxSize>;
46
+ /**
47
+ * If `true`, the component will stretch to the full width of its container.
48
+ * @default false
49
+ */
50
+ stretch?: ZestConfigValue<boolean>;
51
+ /**
52
+ * If `true`, a progress bar indicating character count vs. `maxLength` will be displayed.
53
+ * Requires `maxLength` to be set.
54
+ * @default false
55
+ */
56
+ showProgressBar?: ZestConfigValue<boolean>;
57
+ /**
58
+ * If `true`, the character counter will change color as it approaches the `maxLength`.
59
+ * Requires `maxLength` to be set.
60
+ * @default false
61
+ */
62
+ animatedCounter?: ZestConfigValue<boolean>;
63
+ /**
64
+ * Controls the component's color scheme.
65
+ * `'system'` automatically detects the OS/browser preference.
66
+ * @default 'system'
67
+ */
68
+ theme?: ZestConfigValue<"light" | "dark" | "system">;
69
+ /**
70
+ * If `true`, the component will render as a `<textarea>`.
71
+ * If `false` or undefined, it renders as an `<input>`.
72
+ * @default false
73
+ */
74
+ isMultiline?: ZestConfigValue<boolean>;
75
+ /**
76
+ * A function to parse the raw string input into a desired type.
77
+ * Returns `undefined` if parsing fails.
78
+ */
79
+ parser?: ZestConfigValue<InputParser<any>>;
80
+ /**
81
+ * A function to validate the parsed value.
82
+ * Returns `true` for valid, or a string error message for invalid.
83
+ */
84
+ validator?: ZestConfigValue<InputValidator<any>>;
85
+ }
86
+
87
+ type SharedProps = {
88
+ /**
89
+ * An object containing all custom configurations and behaviors specific to the ZestTextbox component.
90
+ * This encapsulates all non-native HTML input/textarea props for better discoverability and DX.
91
+ * @see ZestProps
92
+ */
93
+ zest?: ZestProps;
94
+ /**
95
+ * A custom CSS class to apply to the main textbox element.
96
+ */
97
+ className?: string;
98
+ /**
99
+ * The maximum number of characters allowed in the input.
100
+ * Enables the character counter.
101
+ */
102
+ maxLength?: number;
103
+ /**
104
+ * The type of the input element. All standard HTML input types are supported.
105
+ * Special handling is applied for `password` and `number`.
106
+ * @default 'text'
107
+ */
108
+ type?: "text" | "email" | "password" | "number" | "tel" | "url" | "search" | "color" | "date" | "datetime-local" | "month" | "time" | "week";
109
+ };
110
+ type InputOnlyProps = SharedProps & Omit<React.InputHTMLAttributes<HTMLInputElement>, "size" | "onChange"> & {
111
+ onChange?: React.ChangeEventHandler<HTMLInputElement>;
112
+ };
113
+ type TextareaOnlyProps = SharedProps & Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, "onChange"> & {
114
+ onChange?: React.ChangeEventHandler<HTMLTextAreaElement>;
115
+ };
116
+ type ZestTextboxProps = InputOnlyProps | TextareaOnlyProps;
117
+ declare const ZestTextbox: React.FC<ZestTextboxProps>;
118
+
119
+ interface PasswordToggleButtonProps {
120
+ isPassword: boolean;
121
+ isPasswordVisible: boolean;
122
+ onToggle: () => void;
123
+ }
124
+ declare const PasswordToggleButton: React.FC<PasswordToggleButtonProps>;
125
+
126
+ interface CharacterCounterProps {
127
+ showCounter: boolean;
128
+ currentLength: number;
129
+ maxLength: number | undefined;
130
+ counterColorClass: string;
131
+ }
132
+ declare const CharacterCounter: React.FC<CharacterCounterProps>;
133
+
134
+ interface ProgressBarProps {
135
+ showProgressBar: boolean;
136
+ showCounter: boolean;
137
+ charPercentage: number;
138
+ counterColorClass: string;
139
+ }
140
+ declare const ProgressBar: React.FC<ProgressBarProps>;
141
+
142
+ interface HelperTextDisplayProps {
143
+ helperTextNode: ReactNode;
144
+ className?: string;
145
+ }
146
+ declare const HelperTextDisplay: React.FC<HelperTextDisplayProps>;
147
+
148
+ interface ZestTextboxConfigProviderProps {
149
+ children: ReactNode;
150
+ value?: ZestProps;
151
+ }
152
+ declare const ZestTextboxConfigProvider: React.FC<ZestTextboxConfigProviderProps>;
153
+
154
+ export { CharacterCounter, HelperTextDisplay, PasswordToggleButton, ProgressBar, ZestTextbox, ZestTextboxConfigProvider };
155
+ export type { HelperTextConfig, ZestProps, ZestTextboxSize };
package/dist/index.esm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
- import { useState, useEffect } from 'react';
2
+ import { useState, useEffect, useMemo, createContext, useContext } from 'react';
3
3
 
4
4
  /******************************************************************************
5
5
  Copyright (c) Microsoft Corporation.
@@ -41,6 +41,44 @@ function __rest(s, e) {
41
41
  return t;
42
42
  }
43
43
 
44
+ function __awaiter(thisArg, _arguments, P, generator) {
45
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
46
+ return new (P || (P = Promise))(function (resolve, reject) {
47
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
48
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
49
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
50
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
51
+ });
52
+ }
53
+
54
+ function __generator(thisArg, body) {
55
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
56
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
57
+ function verb(n) { return function (v) { return step([n, v]); }; }
58
+ function step(op) {
59
+ if (f) throw new TypeError("Generator is already executing.");
60
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
61
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
62
+ if (y = 0, t) op = [op[0] & 2, t.value];
63
+ switch (op[0]) {
64
+ case 0: case 1: t = op; break;
65
+ case 4: _.label++; return { value: op[1], done: false };
66
+ case 5: _.label++; y = op[1]; op = [0]; continue;
67
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
68
+ default:
69
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
70
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
71
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
72
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
73
+ if (t[2]) _.ops.pop();
74
+ _.trys.pop(); continue;
75
+ }
76
+ op = body.call(thisArg, _);
77
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
78
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
79
+ }
80
+ }
81
+
44
82
  typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
45
83
  var e = new Error(message);
46
84
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
@@ -73,24 +111,82 @@ function styleInject(css, ref) {
73
111
  }
74
112
  }
75
113
 
76
- var css_248z = "/* === Base Textbox Styles (input & textarea) === */\n.ZestTextbox-module_textbox__0M5Wq {\n font-family: \"Segoe UI\", Roboto, sans-serif;\n font-weight: 500;\n line-height: 1.25;\n border: 1px solid #ccc;\n border-radius: 0.5rem; /* 8px */\n color: #111827;\n background-color: #ffffff;\n transition: border-color 0.2s ease, box-shadow 0.2s ease;\n display: inline-block;\n width: auto;\n box-sizing: border-box;\n resize: none;\n font-size: 1rem; /* 16px */\n padding-bottom: 2rem; /* 32px */\n}\n\n.ZestTextbox-module_textbox__0M5Wq:focus {\n outline: none;\n border-color: #8B5CF6;\n box-shadow: 0 0 0 0.125rem rgba(139, 92, 246, 0.25); /* 2px */\n animation: ZestTextbox-module_pulse-light__CKfhA 0.5s 1;\n}\n\n/* === Sizes === */\n.ZestTextbox-module_sm__yyxXO {\n padding: 0.5rem 0.75rem; /* 8px 12px */\n font-size: 0.875rem; /* 14px */\n}\n\n.ZestTextbox-module_md__fvL10 {\n padding: 0.625rem 0.875rem; /* 10px 14px */\n font-size: 1rem; /* 16px */\n}\n\n.ZestTextbox-module_lg__fU93- {\n padding: 0.75rem 1rem; /* 12px 16px */\n font-size: 1.125rem; /* 18px */\n}\n\n/* === Full Width === */\n.ZestTextbox-module_fullWidth__xn4fT {\n width: 100%;\n}\n\n/* === Disabled State === */\n.ZestTextbox-module_textbox__0M5Wq:disabled {\n background-color: #f3f4f6;\n color: #9ca3af;\n cursor: not-allowed;\n pointer-events: none;\n border-color: #d1d5db;\n}\n\n/* === Multiline (textarea) specific enhancements === */\ntextarea.ZestTextbox-module_textbox__0M5Wq {\n min-height: 6.25rem; /* 100px */\n line-height: 1.5;\n resize: vertical;\n}\n\n.ZestTextbox-module_wrapper__0ok2A {\n position: relative;\n display: inline-block;\n}\n\n.ZestTextbox-module_counter__waqIT {\n position: absolute;\n right: 0.625rem; /* 10px */\n bottom: 0.375rem; /* 6px */\n font-size: 0.75rem;\n color: #6b7280;\n pointer-events: none;\n user-select: none;\n}\n\n/* === Dark Mode Support === */\n.dark .ZestTextbox-module_textbox__0M5Wq {\n background-color: #1f2937;\n border-color: #374151;\n color: #f3f4f6;\n}\n\n.dark .ZestTextbox-module_textbox__0M5Wq:focus {\n border-color: #A78BFA;\n box-shadow: 0 0 0 0.125rem rgba(167, 139, 250, 0.35); /* 2px */\n animation: ZestTextbox-module_pulse-dark__L9PYJ 0.5s 1;\n}\n\n.dark .ZestTextbox-module_textbox__0M5Wq:disabled {\n background-color: #374151;\n color: #9ca3af;\n border-color: #4b5563;\n}\n\n.dark .ZestTextbox-module_counter__waqIT {\n color: #9ca3af;\n}\n\n/* === Password Toggle === */\n.ZestTextbox-module_passwordToggle__I2s4O {\n position: absolute;\n right: 0.625rem; /* 10px */\n top: 50%;\n transform: translateY(-50%);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #6b7280;\n}\n\n.ZestTextbox-module_eyeIcon__rKiBL {\n width: 1.25em;\n height: 1.25em;\n transition: transform 0.2s ease-in-out;\n}\n\n.ZestTextbox-module_rotate__Ajx19 {\n transform: rotate(180deg);\n}\n\n.ZestTextbox-module_tooltip__etRdj {\n position: absolute;\n right: 100%;\n top: 50%;\n transform: translateY(-50%);\n background-color: #333;\n color: #fff;\n padding: 0.25rem 0.5rem; /* 4px 8px */\n border-radius: 0.25rem; /* 4px */\n font-size: 0.75rem;\n white-space: nowrap;\n margin-right: 0.5rem; /* 8px */\n opacity: 0;\n visibility: hidden;\n transition: opacity 0.2s ease, visibility 0.2s ease;\n}\n\n.ZestTextbox-module_passwordToggle__I2s4O:hover .ZestTextbox-module_tooltip__etRdj {\n opacity: 1;\n visibility: visible;\n}\n\n.dark .ZestTextbox-module_passwordToggle__I2s4O {\n color: #9ca3af;\n}\n\n.dark .ZestTextbox-module_tooltip__etRdj {\n background-color: #4b5563;\n color: #f3f4f6;\n}\n\n/* === Progress Bar === */\n.ZestTextbox-module_progressBarContainer__0qFKf {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 0.1875rem; /* 3px */\n background-color: #e5e7eb;\n border-bottom-left-radius: 0.5rem; /* 8px */\n border-bottom-right-radius: 0.5rem; /* 8px */\n overflow: hidden;\n}\n\n.ZestTextbox-module_progressBar__vwttj {\n height: 100%;\n background-color: #8B5CF6;\n transition: width 0.2s ease, background-color 0.3s ease;\n}\n\n/* === Animated Counter Colors === */\n.ZestTextbox-module_counterYellow__uYGfs {\n color: #A78BFA;\n}\n\n.ZestTextbox-module_counterOrange__b9baX {\n color: #8B5CF6;\n}\n\n.dark .ZestTextbox-module_progressBarContainer__0qFKf {\n background-color: #374151;\n}\n\n.dark .ZestTextbox-module_progressBar__vwttj {\n background-color: #A78BFA;\n}\n\n.dark .ZestTextbox-module_counterYellow__uYGfs {\n color: #C4B5FD;\n}\n\n.dark .ZestTextbox-module_counterOrange__b9baX {\n color: #A78BFA;\n}\n\n@keyframes ZestTextbox-module_pulse-light__CKfhA {\n 0% {\n box-shadow: 0 0 0 0.125rem rgba(139, 92, 246, 0.25); /* 2px */\n }\n 50% {\n box-shadow: 0 0 0 0.25rem rgba(139, 92, 246, 0.35); /* 4px */\n }\n 100% {\n box-shadow: 0 0 0 0.125rem rgba(139, 92, 246, 0.25); /* 2px */\n }\n}\n\n@keyframes ZestTextbox-module_pulse-dark__L9PYJ {\n 0% {\n box-shadow: 0 0 0 0.125rem rgba(167, 139, 250, 0.35); /* 2px */\n }\n 50% {\n box-shadow: 0 0 0 0.25rem rgba(167, 139, 250, 0.45); /* 4px */\n }\n 100% {\n box-shadow: 0 0 0 0.125rem rgba(167, 139, 250, 0.35); /* 2px */\n }\n}\n\n/* === Media Queries for Responsive Design === */\n@media (min-width: 48rem) { /* 768px */\n /* Tablet */\n .ZestTextbox-module_sm__yyxXO {\n font-size: 0.875rem; /* 14px */\n }\n .ZestTextbox-module_md__fvL10 {\n font-size: 1rem; /* 16px */\n }\n .ZestTextbox-module_lg__fU93- {\n font-size: 1.125rem; /* 18px */\n }\n}\n\n@media (min-width: 64rem) { /* 1024px */\n /* Desktop */\n .ZestTextbox-module_sm__yyxXO {\n padding: 0.375rem 0.625rem; /* 6px 10px */\n font-size: 0.875rem; /* 14px */\n }\n .ZestTextbox-module_md__fvL10 {\n padding: 0.625rem 0.875rem; /* 10px 14px */\n font-size: 1rem; /* 16px */\n }\n .ZestTextbox-module_lg__fU93- {\n padding: 0.75rem 1rem; /* 12px 16px */\n font-size: 1.125rem; /* 18px */\n }\n}\n\n/* === Helper Text === */\n.ZestTextbox-module_helperText__4twSg {\n font-size: 0.875rem; /* 14px */\n color: #6b7280;\n margin-top: 0.25rem; /* 4px */\n animation: ZestTextbox-module_fade-slide-in__re-Ln 0.3s ease-out forwards;\n}\n\n.dark .ZestTextbox-module_helperText__4twSg {\n color: #9ca3af;\n}\n\n@keyframes ZestTextbox-module_fade-slide-in__re-Ln {\n from {\n opacity: 0;\n transform: translateY(5px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n";
77
- var styles = {"textbox":"ZestTextbox-module_textbox__0M5Wq","pulse-light":"ZestTextbox-module_pulse-light__CKfhA","sm":"ZestTextbox-module_sm__yyxXO","md":"ZestTextbox-module_md__fvL10","lg":"ZestTextbox-module_lg__fU93-","fullWidth":"ZestTextbox-module_fullWidth__xn4fT","wrapper":"ZestTextbox-module_wrapper__0ok2A","counter":"ZestTextbox-module_counter__waqIT","pulse-dark":"ZestTextbox-module_pulse-dark__L9PYJ","passwordToggle":"ZestTextbox-module_passwordToggle__I2s4O","eyeIcon":"ZestTextbox-module_eyeIcon__rKiBL","rotate":"ZestTextbox-module_rotate__Ajx19","tooltip":"ZestTextbox-module_tooltip__etRdj","progressBarContainer":"ZestTextbox-module_progressBarContainer__0qFKf","progressBar":"ZestTextbox-module_progressBar__vwttj","counterYellow":"ZestTextbox-module_counterYellow__uYGfs","counterOrange":"ZestTextbox-module_counterOrange__b9baX","helperText":"ZestTextbox-module_helperText__4twSg","fade-slide-in":"ZestTextbox-module_fade-slide-in__re-Ln"};
114
+ var css_248z = "/* === Base Textbox Styles (input & textarea) === */\n.ZestTextbox-module_textbox__0M5Wq {\n font-family: \"Segoe UI\", Roboto, sans-serif;\n font-weight: 500;\n line-height: 1.25;\n border: 1px solid #ccc;\n border-radius: 0.5rem; /* 8px */\n color: #111827;\n background-color: #ffffff;\n transition: border-color 0.2s ease, box-shadow 0.2s ease;\n display: inline-block;\n width: auto;\n box-sizing: border-box;\n resize: none;\n font-size: 1rem; /* 16px */\n padding-bottom: 0.5rem; /* Reduced padding to make space for progress bar */\n}\n\n.ZestTextbox-module_textbox__0M5Wq:focus {\n outline: none;\n border-color: #8B5CF6;\n box-shadow: 0 0 0 0.125rem rgba(139, 92, 246, 0.25); /* 2px */\n animation: ZestTextbox-module_pulse-light__CKfhA 0.5s 1;\n}\n\n/* === Error State === */\n.ZestTextbox-module_error__5RoCP {\n border-color: #ef4444; /* Red-500 */\n box-shadow: 0 0 0 0.125rem rgba(239, 68, 68, 0.25); /* Red-500 with 25% opacity */\n}\n\n.ZestTextbox-module_error__5RoCP:focus {\n border-color: #ef4444;\n box-shadow: 0 0 0 0.125rem rgba(239, 68, 68, 0.35);\n}\n\n/* === Sizes === */\n.ZestTextbox-module_sm__yyxXO {\n padding: 0.5rem 0.75rem; /* 8px 12px */\n font-size: 0.875rem; /* 14px */\n}\n\n.ZestTextbox-module_md__fvL10 {\n padding: 0.625rem 0.875rem; /* 10px 14px */\n font-size: 1rem; /* 16px */\n}\n\n.ZestTextbox-module_lg__fU93- {\n padding: 0.75rem 1rem; /* 12px 16px */\n font-size: 1.125rem; /* 18px */\n}\n\n/* === Full Width === */\n.ZestTextbox-module_fullWidth__xn4fT {\n width: 100%;\n}\n\n/* === Disabled State === */\n.ZestTextbox-module_textbox__0M5Wq:disabled {\n background-color: #f3f4f6;\n color: #9ca3af;\n cursor: not-allowed;\n pointer-events: none;\n border-color: #d1d5db;\n}\n\n/* === Multiline (textarea) specific enhancements === */\ntextarea.ZestTextbox-module_textbox__0M5Wq {\n min-height: 6.25rem; /* 100px */\n line-height: 1.5;\n resize: vertical;\n}\n\n.ZestTextbox-module_wrapper__0ok2A {\n position: relative;\n display: inline-block;\n}\n\n.ZestTextbox-module_counter__waqIT {\n position: absolute;\n right: 0.625rem; /* 10px */\n bottom: 0.375rem; /* 6px */\n font-size: 0.75rem;\n color: #6b7280;\n pointer-events: none;\n user-select: none;\n}\n\n/* === Dark Mode Support === */\n.dark .ZestTextbox-module_textbox__0M5Wq {\n background-color: #1f2937;\n border-color: #374151;\n color: #f3f4f6;\n}\n\n.dark .ZestTextbox-module_textbox__0M5Wq:focus {\n border-color: #A78BFA;\n box-shadow: 0 0 0 0.125rem rgba(167, 139, 250, 0.35); /* 2px */\n animation: ZestTextbox-module_pulse-dark__L9PYJ 0.5s 1;\n}\n\n.dark .ZestTextbox-module_textbox__0M5Wq:disabled {\n background-color: #374151;\n color: #9ca3af;\n border-color: #4b5563;\n}\n\n.dark .ZestTextbox-module_counter__waqIT {\n color: #9ca3af;\n}\n\n.dark .ZestTextbox-module_error__5RoCP {\n border-color: #f87171; /* Red-400 for dark mode */\n box-shadow: 0 0 0 0.125rem rgba(248, 113, 113, 0.35);\n}\n\n.dark .ZestTextbox-module_error__5RoCP:focus {\n border-color: #f87171;\n box-shadow: 0 0 0 0.125rem rgba(248, 113, 113, 0.45);\n}\n\n/* === Password Toggle === */\n.ZestTextbox-module_passwordToggle__I2s4O {\n position: absolute;\n right: 0.625rem; /* 10px */\n top: 50%;\n transform: translateY(-50%);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #6b7280;\n}\n\n.ZestTextbox-module_eyeIcon__rKiBL {\n width: 1.25em;\n height: 1.25em;\n transition: transform 0.2s ease-in-out;\n}\n\n.ZestTextbox-module_rotate__Ajx19 {\n transform: rotate(180deg);\n}\n\n.ZestTextbox-module_tooltip__etRdj {\n position: absolute;\n right: 100%;\n top: 50%;\n transform: translateY(-50%);\n background-color: #333;\n color: #fff;\n padding: 0.25rem 0.5rem; /* 4px 8px */\n border-radius: 0.25rem; /* 4px */\n font-size: 0.75rem;\n white-space: nowrap;\n margin-right: 0.5rem; /* 8px */\n opacity: 0;\n visibility: hidden;\n transition: opacity 0.2s ease, visibility 0.2s ease;\n}\n\n.ZestTextbox-module_passwordToggle__I2s4O:hover .ZestTextbox-module_tooltip__etRdj {\n opacity: 1;\n visibility: visible;\n}\n\n.dark .ZestTextbox-module_passwordToggle__I2s4O {\n color: #9ca3af;\n}\n\n.dark .ZestTextbox-module_tooltip__etRdj {\n background-color: #4b5563;\n color: #f3f4f6;\n}\n\n/* === Progress Bar === */\n.ZestTextbox-module_progressBarContainer__0qFKf {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 0.1875rem; /* 3px */\n background-color: #e5e7eb;\n border-bottom-left-radius: 0.5rem; /* 8px */\n border-bottom-right-radius: 0.5rem; /* 8px */\n overflow: hidden;\n}\n\n.ZestTextbox-module_progressBar__vwttj {\n height: 100%;\n background-color: #8B5CF6;\n transition: width 0.2s ease, background-color 0.3s ease;\n}\n\n/* === Animated Counter Colors === */\n.ZestTextbox-module_counterYellow__uYGfs {\n color: #A78BFA;\n}\n\n.ZestTextbox-module_counterOrange__b9baX {\n color: #8B5CF6;\n}\n\n.dark .ZestTextbox-module_progressBarContainer__0qFKf {\n background-color: #374151;\n}\n\n.dark .ZestTextbox-module_progressBar__vwttj {\n background-color: #A78BFA;\n}\n\n.dark .ZestTextbox-module_counterYellow__uYGfs {\n color: #C4B5FD;\n}\n\n.dark .ZestTextbox-module_counterOrange__b9baX {\n color: #A78BFA;\n}\n\n@keyframes ZestTextbox-module_pulse-light__CKfhA {\n 0% {\n box-shadow: 0 0 0 0.125rem rgba(139, 92, 246, 0.25); /* 2px */\n }\n 50% {\n box-shadow: 0 0 0 0.25rem rgba(139, 92, 246, 0.35); /* 4px */\n }\n 100% {\n box-shadow: 0 0 0 0.125rem rgba(139, 92, 246, 0.25); /* 2px */\n }\n}\n\n@keyframes ZestTextbox-module_pulse-dark__L9PYJ {\n 0% {\n box-shadow: 0 0 0 0.125rem rgba(167, 139, 250, 0.35); /* 2px */\n }\n 50% {\n box-shadow: 0 0 0 0.25rem rgba(167, 139, 250, 0.45); /* 4px */\n }\n 100% {\n box-shadow: 0 0 0 0.125rem rgba(167, 139, 250, 0.35); /* 2px */\n }\n}\n\n/* === Media Queries for Responsive Design === */\n@media (min-width: 48rem) { /* 768px */\n /* Tablet */\n .ZestTextbox-module_sm__yyxXO {\n font-size: 0.875rem; /* 14px */\n }\n .ZestTextbox-module_md__fvL10 {\n font-size: 1rem; /* 16px */\n }\n .ZestTextbox-module_lg__fU93- {\n font-size: 1.125rem; /* 18px */\n }\n}\n\n@media (min-width: 64rem) { /* 1024px */\n /* Desktop */\n .ZestTextbox-module_sm__yyxXO {\n padding: 0.375rem 0.625rem; /* 6px 10px */\n font-size: 0.875rem; /* 14px */\n }\n .ZestTextbox-module_md__fvL10 {\n padding: 0.625rem 0.875rem; /* 10px 14px */\n font-size: 1rem; /* 16px */\n }\n .ZestTextbox-module_lg__fU93- {\n padding: 0.75rem 1rem; /* 12px 16px */\n font-size: 1.125rem; /* 18px */\n }\n}\n\n/* === Helper Text === */\n.ZestTextbox-module_helperText__4twSg {\n font-size: 0.875rem; /* 14px */\n color: #6b7280;\n margin-top: 0.25rem; /* 4px */\n animation: ZestTextbox-module_fade-slide-in__re-Ln 0.3s ease-out forwards;\n}\n\n.dark .ZestTextbox-module_helperText__4twSg {\n color: #9ca3af;\n}\n\n@keyframes ZestTextbox-module_fade-slide-in__re-Ln {\n from {\n opacity: 0;\n transform: translateY(5px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}";
115
+ var styles = {"textbox":"ZestTextbox-module_textbox__0M5Wq","pulse-light":"ZestTextbox-module_pulse-light__CKfhA","error":"ZestTextbox-module_error__5RoCP","sm":"ZestTextbox-module_sm__yyxXO","md":"ZestTextbox-module_md__fvL10","lg":"ZestTextbox-module_lg__fU93-","fullWidth":"ZestTextbox-module_fullWidth__xn4fT","wrapper":"ZestTextbox-module_wrapper__0ok2A","counter":"ZestTextbox-module_counter__waqIT","pulse-dark":"ZestTextbox-module_pulse-dark__L9PYJ","passwordToggle":"ZestTextbox-module_passwordToggle__I2s4O","eyeIcon":"ZestTextbox-module_eyeIcon__rKiBL","rotate":"ZestTextbox-module_rotate__Ajx19","tooltip":"ZestTextbox-module_tooltip__etRdj","progressBarContainer":"ZestTextbox-module_progressBarContainer__0qFKf","progressBar":"ZestTextbox-module_progressBar__vwttj","counterYellow":"ZestTextbox-module_counterYellow__uYGfs","counterOrange":"ZestTextbox-module_counterOrange__b9baX","helperText":"ZestTextbox-module_helperText__4twSg","fade-slide-in":"ZestTextbox-module_fade-slide-in__re-Ln"};
78
116
  styleInject(css_248z);
79
117
 
80
- var IconEyeOpen = function (props) { return (jsxs("svg", __assign({ xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", fill: "currentColor", viewBox: "0 0 16 16" }, props, { children: [jsx("path", { d: "M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8M1.173 8a13 13 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5s3.879 1.168 5.168 2.457A13 13 0 0 1 14.828 8q-.086.13-.195.288c-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5s-3.879-1.168-5.168-2.457A13 13 0 0 1 1.172 8z" }), jsx("path", { d: "M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5M4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0" })] }))); };
118
+ var filterNumericInput = function (value) {
119
+ // Allow digits, a single leading hyphen, and a single decimal point
120
+ var parts = value.split('.');
121
+ var integerPart = parts[0].replace(/[^0-9-]/g, '');
122
+ var decimalPart = parts.length > 1 ? '.' + parts[1].replace(/[^0-9]/g, '') : '';
123
+ // Ensure only one leading hyphen
124
+ if (integerPart.startsWith('-')) {
125
+ integerPart = '-' + integerPart.substring(1).replace(/-/g, '');
126
+ }
127
+ else {
128
+ integerPart = integerPart.replace(/-/g, '');
129
+ }
130
+ var newValue = integerPart + decimalPart;
131
+ // Prevent multiple decimal points
132
+ if (newValue.indexOf('.') !== -1 && newValue.indexOf('.') !== newValue.lastIndexOf('.')) {
133
+ newValue = newValue.substring(0, newValue.lastIndexOf('.'));
134
+ }
135
+ return newValue;
136
+ };
81
137
 
82
- var IconEyeSlashed = function (props) { return (jsxs("svg", __assign({ xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", fill: "currentColor", viewBox: "0 0 16 16" }, props, { children: [jsx("path", { d: "M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7.028 7.028 0 0 0-2.79.588l.77.771A5.944 5.944 0 0 1 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.134 13.134 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755-.165.165-.337.328-.517.486l.708.709z" }), jsx("path", { d: "M11.297 9.176a3.5 3.5 0 0 0-4.474-4.474l.823.823a2.5 2.5 0 0 1 2.829 2.829l.822.822zm-2.943 1.288.822.822.073.073.026.026a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829l.822.822zm-2.943-1.288.822.822.073.073.026.026a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829l.822.822z" }), jsx("path", { d: "M3.35 5.47c-.18.16-.353.322-.518.487A13.134 13.134 0 0 0 1.172 8l.195.288c.335.48.83 1.12 1.465 1.755C4.121 11.332 5.88 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7.029 7.029 0 0 1 8 13.5C3 13.5 0 8 0 8s.939-1.721 2.641-3.238l.708.709zm10.296 6.854-12-12 .708-.708 12 12-.708.708z" })] }))); };
138
+ var useThemeDetector = function (theme) {
139
+ if (theme === void 0) { theme = "system"; }
140
+ var _a = useState(false), isDark = _a[0], setIsDark = _a[1];
141
+ useEffect(function () {
142
+ if (theme === "dark") {
143
+ setIsDark(true);
144
+ return;
145
+ }
146
+ if (theme === "light") {
147
+ setIsDark(false);
148
+ return;
149
+ }
150
+ // System theme
151
+ var mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
152
+ var handleChange = function () { return setIsDark(mediaQuery.matches); };
153
+ handleChange(); // Set initial theme
154
+ mediaQuery.addEventListener("change", handleChange);
155
+ return function () { return mediaQuery.removeEventListener("change", handleChange); };
156
+ }, [theme]);
157
+ return isDark;
158
+ };
83
159
 
84
- var ZestTextbox = function (props) {
85
- var _a = props.className, className = _a === void 0 ? "" : _a, maxLength = props.maxLength, onChange = props.onChange, type = props.type, zest = props.zest, // Destructure the new zest prop
86
- rest = __rest(props, ["className", "maxLength", "onChange", "type", "zest"]);
87
- // Destructure custom props from zest, applying defaults if zest is undefined
88
- var _b = zest || {}, _c = _b.zSize, zSize = _c === void 0 ? "md" : _c, _d = _b.stretch, fullWidth = _d === void 0 ? false : _d, _e = _b.showProgressBar, showProgressBar = _e === void 0 ? false : _e, _f = _b.animatedCounter, animatedCounter = _f === void 0 ? false : _f, _g = _b.theme, theme = _g === void 0 ? "system" : _g, helperTextConfig = _b.helperTextConfig, onTextChanged = _b.onTextChanged, _h = _b.isMultiline, isMultiline = _h === void 0 ? false : _h; // Provide empty object as fallback if zest is undefined
89
- var _j = useState(""), value = _j[0], setValue = _j[1];
90
- var _k = useState(false), isDark = _k[0], setIsDark = _k[1];
91
- var _l = useState(false), isPasswordVisible = _l[0], setIsPasswordVisible = _l[1];
92
- var _m = useState(null), helperTextNode = _m[0], setHelperTextNode = _m[1];
93
- // Effect for Helper Text
160
+ var usePasswordVisibility = function (isPasswordType) {
161
+ var _a = useState(false), isPasswordVisible = _a[0], setIsPasswordVisible = _a[1];
162
+ var togglePasswordVisibility = function () {
163
+ if (isPasswordType) {
164
+ setIsPasswordVisible(function (prev) { return !prev; });
165
+ }
166
+ };
167
+ return { isPasswordVisible: isPasswordVisible, togglePasswordVisibility: togglePasswordVisibility };
168
+ };
169
+
170
+ var useCharacterCounter = function (value, maxLength, animatedCounter) {
171
+ var currentLength = value.length;
172
+ var showCounter = typeof maxLength === "number";
173
+ var charPercentage = showCounter ? (currentLength / maxLength) * 100 : 0;
174
+ var counterColorClass = useMemo(function () {
175
+ if (!animatedCounter || !showCounter)
176
+ return "";
177
+ if (charPercentage > 90) {
178
+ return styles.counterOrange;
179
+ }
180
+ else if (charPercentage > 70) {
181
+ return styles.counterYellow;
182
+ }
183
+ return "";
184
+ }, [animatedCounter, showCounter, charPercentage]);
185
+ return { currentLength: currentLength, charPercentage: charPercentage, counterColorClass: counterColorClass, showCounter: showCounter };
186
+ };
187
+
188
+ var useHelperText = function (value, helperTextConfig) {
189
+ var _a = useState(null), helperTextNode = _a[0], setHelperTextNode = _a[1];
94
190
  useEffect(function () {
95
191
  if (!helperTextConfig) {
96
192
  setHelperTextNode(null);
@@ -104,76 +200,252 @@ var ZestTextbox = function (props) {
104
200
  : formatted;
105
201
  setHelperTextNode(finalNode);
106
202
  }, [value, helperTextConfig]);
107
- // Effect for Theme Control
203
+ return helperTextNode;
204
+ };
205
+
206
+ var IconEyeOpen = function (props) { return (jsxs("svg", __assign({ xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", fill: "currentColor", viewBox: "0 0 16 16" }, props, { children: [jsx("path", { d: "M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8M1.173 8a13 13 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5s3.879 1.168 5.168 2.457A13 13 0 0 1 14.828 8q-.086.13-.195.288c-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5s-3.879-1.168-5.168-2.457A13 13 0 0 1 1.172 8z" }), jsx("path", { d: "M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5M4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0" })] }))); };
207
+
208
+ var IconEyeSlashed = function (props) { return (jsxs("svg", __assign({ xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", fill: "currentColor", viewBox: "0 0 16 16" }, props, { children: [jsx("path", { d: "M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7.028 7.028 0 0 0-2.79.588l.77.771A5.944 5.944 0 0 1 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.134 13.134 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755-.165.165-.337.328-.517.486l.708.709z" }), jsx("path", { d: "M11.297 9.176a3.5 3.5 0 0 0-4.474-4.474l.823.823a2.5 2.5 0 0 1 2.829 2.829l.822.822zm-2.943 1.288.822.822.073.073.026.026a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829l.822.822zm-2.943-1.288.822.822.073.073.026.026a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829l.822.822z" }), jsx("path", { d: "M3.35 5.47c-.18.16-.353.322-.518.487A13.134 13.134 0 0 0 1.172 8l.195.288c.335.48.83 1.12 1.465 1.755C4.121 11.332 5.88 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7.029 7.029 0 0 1 8 13.5C3 13.5 0 8 0 8s.939-1.721 2.641-3.238l.708.709zm10.296 6.854-12-12 .708-.708 12 12-.708.708z" })] }))); };
209
+
210
+ var PasswordToggleButton = function (_a) {
211
+ var isPassword = _a.isPassword, isPasswordVisible = _a.isPasswordVisible, onToggle = _a.onToggle;
212
+ if (!isPassword)
213
+ return null;
214
+ return (jsxs("div", { className: styles.passwordToggle, onClick: onToggle, children: [jsx("div", { className: styles.tooltip, children: isPasswordVisible ? "Hide password" : "Show password" }), isPasswordVisible ? (jsx(IconEyeOpen, { className: styles.eyeIcon })) : (jsx(IconEyeSlashed, { className: styles.eyeIcon }))] }));
215
+ };
216
+
217
+ var CharacterCounter = function (_a) {
218
+ var showCounter = _a.showCounter, currentLength = _a.currentLength, maxLength = _a.maxLength, counterColorClass = _a.counterColorClass;
219
+ if (!showCounter)
220
+ return null;
221
+ return (jsxs("div", { className: "".concat(styles.counter, " ").concat(counterColorClass), children: [currentLength, " / ", maxLength] }));
222
+ };
223
+
224
+ var ProgressBar = function (_a) {
225
+ var showProgressBar = _a.showProgressBar, showCounter = _a.showCounter, charPercentage = _a.charPercentage, counterColorClass = _a.counterColorClass;
226
+ if (!showProgressBar || !showCounter)
227
+ return null;
228
+ return (jsx("div", { className: styles.progressBarContainer, children: jsx("div", { className: "".concat(styles.progressBar, " ").concat(counterColorClass), style: { width: "".concat(charPercentage, "%") } }) }));
229
+ };
230
+
231
+ var HelperTextDisplay = function (_a) {
232
+ var helperTextNode = _a.helperTextNode, className = _a.className;
233
+ if (!helperTextNode)
234
+ return null;
235
+ return (jsx("div", { className: "".concat(styles.helperText, " ").concat(className || ""), children: helperTextNode }, String(helperTextNode)));
236
+ };
237
+
238
+ // Create the context with a default empty object
239
+ var ZestTextboxConfigContext = createContext(undefined);
240
+ var ZestTextboxConfigProvider = function (_a) {
241
+ var children = _a.children, _b = _a.value, value = _b === void 0 ? {} : _b;
242
+ return (jsx(ZestTextboxConfigContext.Provider, { value: { defaultZestProps: value }, children: children }));
243
+ };
244
+ // Custom hook to use the ZestTextboxConfigContext
245
+ var useZestTextboxConfig$1 = function () {
246
+ var context = useContext(ZestTextboxConfigContext);
247
+ if (context === undefined) {
248
+ // This error will be caught by the useZestTextboxConfig hook in ZestTextbox.tsx
249
+ // if the component is used outside of a provider.
250
+ return { defaultZestProps: {} };
251
+ }
252
+ return context;
253
+ };
254
+
255
+ // Helper function to resolve a ZestConfigValue
256
+ function resolveZestConfigValue(configValue, defaultValue) {
257
+ return __awaiter(this, void 0, void 0, function () {
258
+ var result, _a;
259
+ return __generator(this, function (_b) {
260
+ switch (_b.label) {
261
+ case 0:
262
+ if (configValue === undefined) {
263
+ return [2 /*return*/, defaultValue];
264
+ }
265
+ if (!(typeof configValue === "function")) return [3 /*break*/, 4];
266
+ result = configValue();
267
+ if (!(result instanceof Promise)) return [3 /*break*/, 2];
268
+ return [4 /*yield*/, result];
269
+ case 1:
270
+ _a = _b.sent();
271
+ return [3 /*break*/, 3];
272
+ case 2:
273
+ _a = result;
274
+ _b.label = 3;
275
+ case 3: return [2 /*return*/, _a];
276
+ case 4: return [2 /*return*/, configValue];
277
+ }
278
+ });
279
+ });
280
+ }
281
+ var defaultResolvedZestProps = {
282
+ zSize: "md",
283
+ stretch: false,
284
+ showProgressBar: false,
285
+ animatedCounter: false,
286
+ theme: "system",
287
+ isMultiline: false,
288
+ onTextChanged: undefined,
289
+ helperTextConfig: undefined,
290
+ parser: undefined,
291
+ validator: undefined,
292
+ };
293
+ var useZestTextboxConfig = function (componentZestProps) {
294
+ var contextDefaultZestProps = useZestTextboxConfig$1().defaultZestProps;
295
+ var _a = useState(defaultResolvedZestProps), resolvedZestProps = _a[0], setResolvedZestProps = _a[1];
296
+ // Memoize the merged props to avoid unnecessary re-renders
297
+ var mergedZestProps = useMemo(function () {
298
+ // Component props take precedence over context default props, which take precedence over hardcoded defaults
299
+ return __assign(__assign(__assign({}, defaultResolvedZestProps), contextDefaultZestProps), componentZestProps);
300
+ }, [contextDefaultZestProps, componentZestProps]);
108
301
  useEffect(function () {
109
- if (theme === "dark") {
110
- setIsDark(true);
111
- return;
302
+ var resolveProps = function () { return __awaiter(void 0, void 0, void 0, function () {
303
+ var newResolvedProps, _a, _b, _c, _d, _e, _f, _g, _h, _j;
304
+ return __generator(this, function (_k) {
305
+ switch (_k.label) {
306
+ case 0:
307
+ newResolvedProps = __assign({}, defaultResolvedZestProps);
308
+ // Resolve each property that can be a ZestConfigValue
309
+ _a = newResolvedProps;
310
+ return [4 /*yield*/, resolveZestConfigValue(mergedZestProps.zSize, defaultResolvedZestProps.zSize)];
311
+ case 1:
312
+ // Resolve each property that can be a ZestConfigValue
313
+ _a.zSize = _k.sent();
314
+ _b = newResolvedProps;
315
+ return [4 /*yield*/, resolveZestConfigValue(mergedZestProps.stretch, defaultResolvedZestProps.stretch)];
316
+ case 2:
317
+ _b.stretch = _k.sent();
318
+ _c = newResolvedProps;
319
+ return [4 /*yield*/, resolveZestConfigValue(mergedZestProps.showProgressBar, defaultResolvedZestProps.showProgressBar)];
320
+ case 3:
321
+ _c.showProgressBar = _k.sent();
322
+ _d = newResolvedProps;
323
+ return [4 /*yield*/, resolveZestConfigValue(mergedZestProps.animatedCounter, defaultResolvedZestProps.animatedCounter)];
324
+ case 4:
325
+ _d.animatedCounter = _k.sent();
326
+ _e = newResolvedProps;
327
+ return [4 /*yield*/, resolveZestConfigValue(mergedZestProps.theme, defaultResolvedZestProps.theme)];
328
+ case 5:
329
+ _e.theme = _k.sent();
330
+ _f = newResolvedProps;
331
+ return [4 /*yield*/, resolveZestConfigValue(mergedZestProps.isMultiline, defaultResolvedZestProps.isMultiline)];
332
+ case 6:
333
+ _f.isMultiline = _k.sent();
334
+ // onTextChanged is no longer a ZestConfigValue, so it's directly assigned
335
+ newResolvedProps.onTextChanged = mergedZestProps.onTextChanged;
336
+ _g = newResolvedProps;
337
+ return [4 /*yield*/, resolveZestConfigValue(mergedZestProps.helperTextConfig, defaultResolvedZestProps.helperTextConfig)];
338
+ case 7:
339
+ _g.helperTextConfig = _k.sent();
340
+ _h = newResolvedProps;
341
+ return [4 /*yield*/, resolveZestConfigValue(mergedZestProps.parser, defaultResolvedZestProps.parser)];
342
+ case 8:
343
+ _h.parser = _k.sent();
344
+ _j = newResolvedProps;
345
+ return [4 /*yield*/, resolveZestConfigValue(mergedZestProps.validator, defaultResolvedZestProps.validator)];
346
+ case 9:
347
+ _j.validator = _k.sent();
348
+ setResolvedZestProps(newResolvedProps);
349
+ return [2 /*return*/];
350
+ }
351
+ });
352
+ }); };
353
+ resolveProps();
354
+ }, [mergedZestProps]); // Re-run effect if merged props change
355
+ return resolvedZestProps;
356
+ };
357
+
358
+ var useParsedAndValidatedInput = function (_a) {
359
+ var rawValue = _a.rawValue, parser = _a.parser, validator = _a.validator, onParsedAndValidatedChange = _a.onParsedAndValidatedChange;
360
+ var _b = useState(undefined), parsedValue = _b[0], setParsedValue = _b[1];
361
+ var _c = useState(true), isValid = _c[0], setIsValid = _c[1];
362
+ var _d = useState(undefined), validationMessage = _d[0], setValidationMessage = _d[1];
363
+ useEffect(function () {
364
+ var currentParsedValue = undefined;
365
+ var currentIsValid = true;
366
+ var currentValidationMessage = undefined;
367
+ // 1. Parse the raw value
368
+ if (parser) {
369
+ currentParsedValue = parser(rawValue);
112
370
  }
113
- if (theme === "light") {
114
- setIsDark(false);
115
- return;
371
+ else {
372
+ // If no parser, treat rawValue as the parsed value (e.g., for text inputs)
373
+ currentParsedValue = rawValue;
116
374
  }
117
- // System theme
118
- var mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
119
- var handleChange = function () { return setIsDark(mediaQuery.matches); };
120
- handleChange(); // Set initial theme
121
- mediaQuery.addEventListener("change", handleChange);
122
- return function () { return mediaQuery.removeEventListener("change", handleChange); };
123
- }, [theme]);
375
+ // 2. Validate the parsed value
376
+ if (validator) {
377
+ var validationResult = validator(currentParsedValue);
378
+ if (typeof validationResult === "string") {
379
+ currentIsValid = false;
380
+ currentValidationMessage = validationResult;
381
+ }
382
+ else {
383
+ currentIsValid = validationResult;
384
+ if (!currentIsValid) {
385
+ currentValidationMessage = "Invalid input."; // Generic message if validator returns false
386
+ }
387
+ }
388
+ }
389
+ setParsedValue(currentParsedValue);
390
+ setIsValid(currentIsValid);
391
+ setValidationMessage(currentValidationMessage);
392
+ // 3. Call the consumer's callback with the parsed and validated value
393
+ // Only call if a callback is provided and the input is valid
394
+ if (onParsedAndValidatedChange && currentIsValid) {
395
+ onParsedAndValidatedChange(currentParsedValue);
396
+ }
397
+ }, [rawValue, parser, validator, onParsedAndValidatedChange]);
398
+ return { parsedValue: parsedValue, isValid: isValid, validationMessage: validationMessage };
399
+ };
400
+
401
+ // ... other imports
402
+ var ZestTextbox = function (props) {
403
+ var _a = props.className, className = _a === void 0 ? "" : _a, maxLength = props.maxLength, onChange = props.onChange, type = props.type, zest = props.zest, // Destructure the new zest prop
404
+ rest = __rest(props, ["className", "maxLength", "onChange", "type", "zest"]);
405
+ var resolvedZestProps = useZestTextboxConfig(zest);
406
+ var zSize = resolvedZestProps.zSize, fullWidth = resolvedZestProps.stretch, showProgressBar = resolvedZestProps.showProgressBar, animatedCounter = resolvedZestProps.animatedCounter, theme = resolvedZestProps.theme, helperTextConfig = resolvedZestProps.helperTextConfig, onTextChanged = resolvedZestProps.onTextChanged, isMultiline = resolvedZestProps.isMultiline, parser = resolvedZestProps.parser, validator = resolvedZestProps.validator;
407
+ var _b = useState(""), value = _b[0], setValue = _b[1];
408
+ var isDark = useThemeDetector(theme);
409
+ var isPassword = type === "password";
410
+ var _c = usePasswordVisibility(isPassword), isPasswordVisible = _c.isPasswordVisible, togglePasswordVisibility = _c.togglePasswordVisibility;
411
+ var _d = useCharacterCounter(value, maxLength, animatedCounter), currentLength = _d.currentLength, charPercentage = _d.charPercentage, counterColorClass = _d.counterColorClass, showCounter = _d.showCounter;
412
+ var _e = useParsedAndValidatedInput({
413
+ rawValue: value,
414
+ parser: parser,
415
+ validator: validator,
416
+ onParsedAndValidatedChange: onTextChanged,
417
+ }), isValid = _e.isValid, validationMessage = _e.validationMessage;
418
+ // Prioritize validation message over regular helper text
419
+ var finalHelperTextNode = validationMessage ? (jsx("span", { style: { color: "red" }, children: validationMessage })) : useHelperText(value, helperTextConfig);
124
420
  var classList = [
125
421
  styles.textbox,
126
422
  styles[zSize],
127
423
  fullWidth ? styles.fullWidth : "",
128
424
  className,
129
425
  isDark ? styles.dark : "",
426
+ !isValid ? styles.error : "", // Add error class if not valid
130
427
  ]
131
428
  .filter(Boolean)
132
429
  .join(" ");
133
430
  var handleInputChange = function (e) {
134
431
  var newValue = e.target.value;
432
+ var isNumeric = type === "number" || type === "tel";
135
433
  if (isNumeric) {
136
- // Allow digits, a single leading hyphen, and a single decimal point
137
- var parts = newValue.split('.');
138
- var integerPart = parts[0].replace(/[^0-9-]/g, '');
139
- var decimalPart = parts.length > 1 ? '.' + parts[1].replace(/[^0-9]/g, '') : '';
140
- // Ensure only one leading hyphen
141
- if (integerPart.startsWith('-')) {
142
- integerPart = '-' + integerPart.substring(1).replace(/-/g, '');
143
- }
144
- else {
145
- integerPart = integerPart.replace(/-/g, '');
146
- }
147
- newValue = integerPart + decimalPart;
148
- // Prevent multiple decimal points
149
- if (newValue.indexOf('.') !== newValue.lastIndexOf('.')) {
150
- newValue = newValue.substring(0, newValue.lastIndexOf('.'));
151
- }
434
+ newValue = filterNumericInput(newValue);
152
435
  }
153
436
  if (maxLength !== undefined && newValue.length > maxLength)
154
437
  return;
155
438
  setValue(newValue);
156
439
  if (onChange)
157
440
  onChange(e);
158
- if (onTextChanged)
159
- onTextChanged(newValue);
441
+ // onTextChanged is now handled by useParsedAndValidatedInput
160
442
  };
161
- var isPassword = type === "password";
162
443
  var isNumeric = type === "number" || type === "tel";
163
444
  var inputType = isPassword && isPasswordVisible ? "text" : isNumeric ? "tel" : type;
164
445
  var commonProps = __assign({ className: classList, maxLength: maxLength, onChange: handleInputChange, value: value, type: inputType }, rest);
165
- var showCounter = typeof maxLength === "number";
166
- var charPercentage = showCounter ? (value.length / maxLength) * 100 : 0;
167
- var counterColorClass = animatedCounter
168
- ? charPercentage > 90
169
- ? styles.counterOrange
170
- : charPercentage > 70
171
- ? styles.counterYellow
172
- : ""
173
- : "";
174
446
  return (jsxs("div", { className: styles.wrapper, children: [isMultiline ? ( // Use isMultiline from zest
175
- jsx("textarea", __assign({}, commonProps))) : (jsx("input", __assign({}, commonProps))), helperTextNode && (jsx("div", { className: "".concat(styles.helperText, " ").concat((helperTextConfig === null || helperTextConfig === void 0 ? void 0 : helperTextConfig.className) || ''), children: helperTextNode }, value)), showCounter && (jsxs("div", { className: "".concat(styles.counter, " ").concat(counterColorClass), children: [value.length, " / ", maxLength] })), isPassword && (jsxs("div", { className: styles.passwordToggle, onClick: function () { return setIsPasswordVisible(!isPasswordVisible); }, children: [jsx("div", { className: styles.tooltip, children: isPasswordVisible ? "Hide password" : "Show password" }), isPasswordVisible ? (jsx(IconEyeOpen, { className: styles.eyeIcon })) : (jsx(IconEyeSlashed, { className: styles.eyeIcon }))] })), showProgressBar && showCounter && (jsx("div", { className: styles.progressBarContainer, children: jsx("div", { className: "".concat(styles.progressBar, " ").concat(counterColorClass), style: { width: "".concat(charPercentage, "%") } }) }))] }));
447
+ jsx("textarea", __assign({}, commonProps))) : (jsx("input", __assign({}, commonProps))), jsx(HelperTextDisplay, { helperTextNode: finalHelperTextNode, className: (helperTextConfig === null || helperTextConfig === void 0 ? void 0 : helperTextConfig.className) || '' }), jsx(CharacterCounter, { showCounter: showCounter, currentLength: currentLength, maxLength: maxLength, counterColorClass: counterColorClass }), jsx(PasswordToggleButton, { isPassword: isPassword, isPasswordVisible: isPasswordVisible, onToggle: togglePasswordVisibility }), jsx(ProgressBar, { showProgressBar: showProgressBar, showCounter: showCounter, charPercentage: charPercentage, counterColorClass: counterColorClass })] }));
176
448
  };
177
449
 
178
- export { ZestTextbox as default };
450
+ export { CharacterCounter, HelperTextDisplay, PasswordToggleButton, ProgressBar, ZestTextbox, ZestTextboxConfigProvider };
179
451
  //# sourceMappingURL=index.esm.js.map