@rovula/ui 0.0.76 → 0.0.77

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 (41) hide show
  1. package/dist/cjs/bundle.css +12 -0
  2. package/dist/cjs/bundle.js +3 -3
  3. package/dist/cjs/bundle.js.map +1 -1
  4. package/dist/cjs/types/components/Dropdown/Dropdown.stories.d.ts +7 -0
  5. package/dist/cjs/types/components/InputFilter/InputFilter.stories.d.ts +7 -0
  6. package/dist/cjs/types/components/NumberInput/NumberInput.d.ts +39 -0
  7. package/dist/cjs/types/components/NumberInput/NumberInput.stories.d.ts +18 -0
  8. package/dist/cjs/types/components/NumberInput/index.d.ts +2 -0
  9. package/dist/cjs/types/components/RadioGroup/RadioGroup.stories.d.ts +1 -1
  10. package/dist/cjs/types/components/Search/Search.stories.d.ts +7 -0
  11. package/dist/cjs/types/components/Slider/Slider.stories.d.ts +1 -1
  12. package/dist/cjs/types/components/TextInput/TextInput.d.ts +14 -0
  13. package/dist/cjs/types/components/TextInput/TextInput.stories.d.ts +14 -0
  14. package/dist/cjs/types/index.d.ts +2 -0
  15. package/dist/components/NumberInput/NumberInput.js +254 -0
  16. package/dist/components/NumberInput/NumberInput.stories.js +212 -0
  17. package/dist/components/NumberInput/index.js +1 -0
  18. package/dist/components/TextInput/TextInput.js +13 -11
  19. package/dist/esm/bundle.css +12 -0
  20. package/dist/esm/bundle.js +3 -3
  21. package/dist/esm/bundle.js.map +1 -1
  22. package/dist/esm/types/components/Dropdown/Dropdown.stories.d.ts +7 -0
  23. package/dist/esm/types/components/InputFilter/InputFilter.stories.d.ts +7 -0
  24. package/dist/esm/types/components/NumberInput/NumberInput.d.ts +39 -0
  25. package/dist/esm/types/components/NumberInput/NumberInput.stories.d.ts +18 -0
  26. package/dist/esm/types/components/NumberInput/index.d.ts +2 -0
  27. package/dist/esm/types/components/RadioGroup/RadioGroup.stories.d.ts +1 -1
  28. package/dist/esm/types/components/Search/Search.stories.d.ts +7 -0
  29. package/dist/esm/types/components/Slider/Slider.stories.d.ts +1 -1
  30. package/dist/esm/types/components/TextInput/TextInput.d.ts +14 -0
  31. package/dist/esm/types/components/TextInput/TextInput.stories.d.ts +14 -0
  32. package/dist/esm/types/index.d.ts +2 -0
  33. package/dist/index.d.ts +52 -1
  34. package/dist/index.js +1 -0
  35. package/dist/src/theme/global.css +16 -0
  36. package/package.json +1 -1
  37. package/src/components/NumberInput/NumberInput.stories.tsx +350 -0
  38. package/src/components/NumberInput/NumberInput.tsx +428 -0
  39. package/src/components/NumberInput/index.ts +2 -0
  40. package/src/components/TextInput/TextInput.tsx +54 -12
  41. package/src/index.ts +2 -0
@@ -362,6 +362,13 @@ declare const meta: {
362
362
  iconMode?: "flat" | "solid" | undefined;
363
363
  keepCloseIconOnValue?: boolean | undefined;
364
364
  labelClassName?: string | undefined;
365
+ classes?: {
366
+ iconWrapper?: string;
367
+ iconSearchWrapper?: string;
368
+ icon?: string;
369
+ startIconWrapper?: string;
370
+ endIconWrapper?: string;
371
+ } | undefined;
365
372
  onClickStartIcon?: (() => void) | undefined;
366
373
  onClickEndIcon?: (() => void) | undefined;
367
374
  renderStartIcon?: (() => React.ReactNode) | undefined;
@@ -352,6 +352,13 @@ declare const meta: {
352
352
  iconMode?: "flat" | "solid" | undefined;
353
353
  keepCloseIconOnValue?: boolean | undefined;
354
354
  labelClassName?: string | undefined;
355
+ classes?: {
356
+ iconWrapper?: string;
357
+ iconSearchWrapper?: string;
358
+ icon?: string;
359
+ startIconWrapper?: string;
360
+ endIconWrapper?: string;
361
+ } | undefined;
355
362
  onClickStartIcon?: (() => void) | undefined;
356
363
  onClickEndIcon?: (() => void) | undefined;
357
364
  renderStartIcon?: (() => React.ReactNode) | undefined;
@@ -0,0 +1,39 @@
1
+ import React from "react";
2
+ import { InputProps as TextInputProps } from "../TextInput/TextInput";
3
+ export type NumberInputProps = Omit<TextInputProps, "type" | "value" | "defaultValue" | "onChange"> & {
4
+ value?: number | string;
5
+ defaultValue?: number | string;
6
+ min?: number;
7
+ max?: number;
8
+ step?: number;
9
+ precision?: number;
10
+ hideControls?: boolean;
11
+ allowDecimal?: boolean;
12
+ allowNegative?: boolean;
13
+ formatDisplay?: boolean;
14
+ thousandSeparator?: string;
15
+ decimalSeparator?: string;
16
+ prefix?: string;
17
+ suffix?: string;
18
+ onChange?: (value: number | undefined) => void;
19
+ onValueChange?: (value: string) => void;
20
+ };
21
+ export declare const NumberInput: React.ForwardRefExoticComponent<Omit<TextInputProps, "type" | "onChange" | "value" | "defaultValue"> & {
22
+ value?: number | string;
23
+ defaultValue?: number | string;
24
+ min?: number;
25
+ max?: number;
26
+ step?: number;
27
+ precision?: number;
28
+ hideControls?: boolean;
29
+ allowDecimal?: boolean;
30
+ allowNegative?: boolean;
31
+ formatDisplay?: boolean;
32
+ thousandSeparator?: string;
33
+ decimalSeparator?: string;
34
+ prefix?: string;
35
+ suffix?: string;
36
+ onChange?: (value: number | undefined) => void;
37
+ onValueChange?: (value: string) => void;
38
+ } & React.RefAttributes<HTMLInputElement>>;
39
+ export default NumberInput;
@@ -0,0 +1,18 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { NumberInput } from "@/index";
3
+ declare const meta: Meta<typeof NumberInput>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof NumberInput>;
6
+ export declare const Default: Story;
7
+ export declare const WithMinMax: Story;
8
+ export declare const WithStep: Story;
9
+ export declare const IntegerOnly: Story;
10
+ export declare const ControllWithOutLine: Story;
11
+ export declare const WithoutControls: Story;
12
+ export declare const ErrorState: Story;
13
+ export declare const HelperText: Story;
14
+ export declare const Disabled: Story;
15
+ export declare const FormattedNumber: Story;
16
+ export declare const CurrencyFormat: Story;
17
+ export declare const CurrencyThailand: Story;
18
+ export declare const CustomSeparators: Story;
@@ -0,0 +1,2 @@
1
+ export { NumberInput, default } from "./NumberInput";
2
+ export type { NumberInputProps } from "./NumberInput";
@@ -279,9 +279,9 @@ declare const meta: {
279
279
  inputMode?: "none" | "text" | "tel" | "url" | "email" | "numeric" | "decimal" | "search" | undefined | undefined;
280
280
  is?: string | undefined | undefined;
281
281
  required?: boolean | undefined;
282
+ onValueChange?: ((value: string) => void) | undefined;
282
283
  loop?: boolean | undefined;
283
284
  asChild?: boolean | undefined;
284
- onValueChange?: ((value: string) => void) | undefined;
285
285
  ref?: React.LegacyRef<HTMLDivElement> | undefined;
286
286
  }>) => import("react/jsx-runtime").JSX.Element)[];
287
287
  };
@@ -314,6 +314,13 @@ declare const meta: {
314
314
  helperText?: string | undefined;
315
315
  errorMessage?: string | undefined;
316
316
  labelClassName?: string | undefined;
317
+ classes?: {
318
+ iconWrapper?: string;
319
+ iconSearchWrapper?: string;
320
+ icon?: string;
321
+ startIconWrapper?: string;
322
+ endIconWrapper?: string;
323
+ } | undefined;
317
324
  onClickStartIcon?: (() => void) | undefined;
318
325
  onClickEndIcon?: (() => void) | undefined;
319
326
  renderStartIcon?: (() => React.ReactNode) | undefined;
@@ -289,10 +289,10 @@ declare const meta: {
289
289
  unselectable?: "on" | "off" | undefined | undefined;
290
290
  inputMode?: "none" | "text" | "tel" | "url" | "email" | "numeric" | "decimal" | "search" | undefined | undefined;
291
291
  is?: string | undefined | undefined;
292
+ onValueChange?: ((value: number[]) => void) | undefined;
292
293
  asChild?: boolean | undefined;
293
294
  inverted?: boolean | undefined;
294
295
  minStepsBetweenThumbs?: number | undefined;
295
- onValueChange?: ((value: number[]) => void) | undefined;
296
296
  onValueCommit?: ((value: number[]) => void) | undefined;
297
297
  ref?: React.LegacyRef<HTMLSpanElement> | undefined;
298
298
  }>) => import("react/jsx-runtime").JSX.Element)[];
@@ -21,6 +21,13 @@ export type InputProps = {
21
21
  endIcon?: ReactNode;
22
22
  className?: string;
23
23
  labelClassName?: string;
24
+ classes?: {
25
+ iconWrapper?: string;
26
+ iconSearchWrapper?: string;
27
+ icon?: string;
28
+ startIconWrapper?: string;
29
+ endIconWrapper?: string;
30
+ };
24
31
  onClickStartIcon?: () => void;
25
32
  onClickEndIcon?: () => void;
26
33
  renderStartIcon?: () => ReactNode;
@@ -48,6 +55,13 @@ export declare const TextInput: React.ForwardRefExoticComponent<{
48
55
  endIcon?: ReactNode;
49
56
  className?: string;
50
57
  labelClassName?: string;
58
+ classes?: {
59
+ iconWrapper?: string;
60
+ iconSearchWrapper?: string;
61
+ icon?: string;
62
+ startIconWrapper?: string;
63
+ endIconWrapper?: string;
64
+ };
51
65
  onClickStartIcon?: () => void;
52
66
  onClickEndIcon?: () => void;
53
67
  renderStartIcon?: () => ReactNode;
@@ -23,6 +23,13 @@ declare const meta: {
23
23
  endIcon?: React.ReactNode;
24
24
  className?: string;
25
25
  labelClassName?: string;
26
+ classes?: {
27
+ iconWrapper?: string;
28
+ iconSearchWrapper?: string;
29
+ icon?: string;
30
+ startIconWrapper?: string;
31
+ endIconWrapper?: string;
32
+ };
26
33
  onClickStartIcon?: () => void;
27
34
  onClickEndIcon?: () => void;
28
35
  renderStartIcon?: () => React.ReactNode;
@@ -54,6 +61,13 @@ declare const meta: {
54
61
  endIcon?: React.ReactNode;
55
62
  className?: string | undefined;
56
63
  labelClassName?: string | undefined;
64
+ classes?: {
65
+ iconWrapper?: string;
66
+ iconSearchWrapper?: string;
67
+ icon?: string;
68
+ startIconWrapper?: string;
69
+ endIconWrapper?: string;
70
+ } | undefined;
57
71
  onClickStartIcon?: (() => void) | undefined;
58
72
  onClickEndIcon?: (() => void) | undefined;
59
73
  renderStartIcon?: (() => React.ReactNode) | undefined;
@@ -2,6 +2,7 @@ import "./theme/global.css";
2
2
  import "./icons/iconConfig";
3
3
  export { default as Button } from "./components/Button/Button";
4
4
  export { default as TextInput } from "./components/TextInput/TextInput";
5
+ export { NumberInput } from "./components/NumberInput/NumberInput";
5
6
  export { default as TextArea } from "./components/TextArea/TextArea";
6
7
  export { default as Text } from "./components/Text/Text";
7
8
  export { default as Tabs } from "./components/Tabs/Tabs";
@@ -38,6 +39,7 @@ export * from "./components/FocusedScrollView/FocusedScrollView";
38
39
  export * from "./components/RadioGroup/RadioGroup";
39
40
  export type { ButtonProps } from "./components/Button/Button";
40
41
  export type { InputProps } from "./components/TextInput/TextInput";
42
+ export type { NumberInputProps } from "./components/NumberInput/NumberInput";
41
43
  export type { TextAreaProps } from "./components/TextArea/TextArea";
42
44
  export type { DropdownProps, Options } from "./components/Dropdown/Dropdown";
43
45
  export type { NavbarProps } from "./components/Navbar/Navbar";
@@ -0,0 +1,254 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ import React, { forwardRef, useCallback, useImperativeHandle, useRef, useState, } from "react";
14
+ import { TextInput, } from "../TextInput/TextInput";
15
+ import { ChevronUpIcon, ChevronDownIcon } from "@heroicons/react/16/solid";
16
+ import { cn } from "@/utils/cn";
17
+ export const NumberInput = forwardRef((_a, ref) => {
18
+ var _b;
19
+ var { value, defaultValue, min, max, step = 1, precision, hideControls = false, allowDecimal = true, allowNegative = true, formatDisplay = false, thousandSeparator = ",", decimalSeparator = ".", prefix = "", suffix = "", disabled = false, onChange, onValueChange, className, size = "md" } = _a, props = __rest(_a, ["value", "defaultValue", "min", "max", "step", "precision", "hideControls", "allowDecimal", "allowNegative", "formatDisplay", "thousandSeparator", "decimalSeparator", "prefix", "suffix", "disabled", "onChange", "onValueChange", "className", "size"]);
20
+ const inputRef = useRef(null);
21
+ const [internalValue, setInternalValue] = useState(((_b = value !== null && value !== void 0 ? value : defaultValue) !== null && _b !== void 0 ? _b : "").toString());
22
+ const [isFocused, setIsFocused] = useState(false);
23
+ useImperativeHandle(ref, () => inputRef === null || inputRef === void 0 ? void 0 : inputRef.current);
24
+ // Helper function to remove formatting
25
+ const unformatNumber = useCallback((formattedValue) => {
26
+ let cleaned = formattedValue;
27
+ // Remove prefix and suffix
28
+ if (prefix)
29
+ cleaned = cleaned.replace(prefix, "");
30
+ if (suffix)
31
+ cleaned = cleaned.replace(suffix, "");
32
+ // Remove thousand separators
33
+ if (thousandSeparator) {
34
+ cleaned = cleaned.split(thousandSeparator).join("");
35
+ }
36
+ // Replace decimal separator with standard dot
37
+ if (decimalSeparator !== ".") {
38
+ cleaned = cleaned.replace(decimalSeparator, ".");
39
+ }
40
+ return cleaned.trim();
41
+ }, [prefix, suffix, thousandSeparator, decimalSeparator]);
42
+ // Helper function to format number for display
43
+ const formatNumber = useCallback((numValue) => {
44
+ if (!formatDisplay || numValue === "" || numValue === "-")
45
+ return numValue;
46
+ const num = parseFloat(numValue);
47
+ if (isNaN(num))
48
+ return numValue;
49
+ let formatted = num.toString();
50
+ // Apply precision formatting
51
+ if (precision !== undefined) {
52
+ formatted = num.toFixed(precision);
53
+ }
54
+ // Split into integer and decimal parts
55
+ const parts = formatted.split(".");
56
+ let integerPart = parts[0];
57
+ const decimalPart = parts[1];
58
+ // Add thousand separators
59
+ if (thousandSeparator) {
60
+ integerPart = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, thousandSeparator);
61
+ }
62
+ // Combine with decimal separator
63
+ formatted = decimalPart
64
+ ? `${integerPart}${decimalSeparator}${decimalPart}`
65
+ : integerPart;
66
+ // Add prefix and suffix
67
+ if (prefix)
68
+ formatted = `${prefix}${formatted}`;
69
+ if (suffix)
70
+ formatted = `${formatted}${suffix}`;
71
+ return formatted;
72
+ }, [
73
+ formatDisplay,
74
+ precision,
75
+ thousandSeparator,
76
+ decimalSeparator,
77
+ prefix,
78
+ suffix,
79
+ ]);
80
+ const validateAndFormat = useCallback((val) => {
81
+ if (val === "" || val === "-")
82
+ return val;
83
+ let numValue = parseFloat(val);
84
+ if (isNaN(numValue))
85
+ return internalValue;
86
+ // Apply min/max constraints
87
+ if (min !== undefined && numValue < min)
88
+ numValue = min;
89
+ if (max !== undefined && numValue > max)
90
+ numValue = max;
91
+ // Apply precision
92
+ if (precision !== undefined) {
93
+ numValue = parseFloat(numValue.toFixed(precision));
94
+ }
95
+ return numValue.toString();
96
+ }, [min, max, precision, internalValue]);
97
+ const handleInputChange = useCallback((e) => {
98
+ let inputValue = e.target.value;
99
+ // Unformat the input if formatting is enabled
100
+ if (formatDisplay) {
101
+ inputValue = unformatNumber(inputValue);
102
+ }
103
+ // Allow empty input
104
+ if (inputValue === "") {
105
+ setInternalValue("");
106
+ onChange === null || onChange === void 0 ? void 0 : onChange(undefined);
107
+ onValueChange === null || onValueChange === void 0 ? void 0 : onValueChange("");
108
+ return;
109
+ }
110
+ // Allow negative sign at the start
111
+ if (allowNegative && inputValue === "-") {
112
+ setInternalValue("-");
113
+ onValueChange === null || onValueChange === void 0 ? void 0 : onValueChange("-");
114
+ return;
115
+ }
116
+ // Filter non-numeric characters based on settings
117
+ const regex = allowDecimal
118
+ ? allowNegative
119
+ ? /^-?\d*\.?\d*$/
120
+ : /^\d*\.?\d*$/
121
+ : allowNegative
122
+ ? /^-?\d*$/
123
+ : /^\d*$/;
124
+ if (!regex.test(inputValue)) {
125
+ return;
126
+ }
127
+ setInternalValue(inputValue);
128
+ onValueChange === null || onValueChange === void 0 ? void 0 : onValueChange(inputValue);
129
+ // Only call onChange with a valid number
130
+ const numValue = parseFloat(inputValue);
131
+ if (!isNaN(numValue)) {
132
+ onChange === null || onChange === void 0 ? void 0 : onChange(numValue);
133
+ }
134
+ }, [
135
+ allowDecimal,
136
+ allowNegative,
137
+ formatDisplay,
138
+ unformatNumber,
139
+ onChange,
140
+ onValueChange,
141
+ ]);
142
+ const handleFocus = useCallback((e) => {
143
+ var _a;
144
+ setIsFocused(true);
145
+ (_a = props.onFocus) === null || _a === void 0 ? void 0 : _a.call(props, e);
146
+ }, [props]);
147
+ const handleBlur = useCallback((e) => {
148
+ var _a;
149
+ setIsFocused(false);
150
+ const formatted = validateAndFormat(internalValue);
151
+ setInternalValue(formatted);
152
+ const numValue = parseFloat(formatted);
153
+ if (!isNaN(numValue)) {
154
+ onChange === null || onChange === void 0 ? void 0 : onChange(numValue);
155
+ }
156
+ (_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, e);
157
+ }, [internalValue, validateAndFormat, onChange, props]);
158
+ const increment = useCallback((e) => {
159
+ if (disabled)
160
+ return;
161
+ e.stopPropagation();
162
+ e.preventDefault();
163
+ const currentValue = parseFloat(internalValue) || 0;
164
+ let newValue = currentValue + step;
165
+ if (max !== undefined && newValue > max) {
166
+ newValue = max;
167
+ }
168
+ const formatted = validateAndFormat(newValue.toString());
169
+ setInternalValue(formatted);
170
+ onChange === null || onChange === void 0 ? void 0 : onChange(parseFloat(formatted));
171
+ onValueChange === null || onValueChange === void 0 ? void 0 : onValueChange(formatted);
172
+ }, [
173
+ internalValue,
174
+ step,
175
+ max,
176
+ disabled,
177
+ validateAndFormat,
178
+ onChange,
179
+ onValueChange,
180
+ ]);
181
+ const decrement = useCallback((e) => {
182
+ if (disabled)
183
+ return;
184
+ e.stopPropagation();
185
+ e.preventDefault();
186
+ const currentValue = parseFloat(internalValue) || 0;
187
+ let newValue = currentValue - step;
188
+ if (min !== undefined && newValue < min) {
189
+ newValue = min;
190
+ }
191
+ const formatted = validateAndFormat(newValue.toString());
192
+ setInternalValue(formatted);
193
+ onChange === null || onChange === void 0 ? void 0 : onChange(parseFloat(formatted));
194
+ onValueChange === null || onValueChange === void 0 ? void 0 : onValueChange(formatted);
195
+ }, [
196
+ internalValue,
197
+ step,
198
+ min,
199
+ disabled,
200
+ validateAndFormat,
201
+ onChange,
202
+ onValueChange,
203
+ ]);
204
+ const handleKeyDown = useCallback((e) => {
205
+ var _a;
206
+ switch (e.key) {
207
+ case "ArrowUp":
208
+ increment(e);
209
+ break;
210
+ case "ArrowDown":
211
+ decrement(e);
212
+ break;
213
+ case "Enter":
214
+ e.currentTarget.blur();
215
+ break;
216
+ default:
217
+ break;
218
+ }
219
+ (_a = props.onKeyDown) === null || _a === void 0 ? void 0 : _a.call(props, e);
220
+ }, [increment, decrement, props]);
221
+ // Sync internal value with external value prop
222
+ React.useEffect(() => {
223
+ if (value !== undefined) {
224
+ setInternalValue(value.toString());
225
+ }
226
+ }, [value]);
227
+ // Get the display value (formatted when not focused)
228
+ const displayValue = React.useMemo(() => {
229
+ if (isFocused || !formatDisplay) {
230
+ return internalValue;
231
+ }
232
+ return formatNumber(internalValue);
233
+ }, [isFocused, formatDisplay, internalValue, formatNumber]);
234
+ const controlsSize = {
235
+ sm: "w-3 h-3",
236
+ md: "w-4 h-4",
237
+ lg: "w-6 h-6",
238
+ }[size];
239
+ const paddingSize = {
240
+ sm: "absolute top-0.5",
241
+ md: "absolute top-1",
242
+ lg: "absolute top-1",
243
+ }[size];
244
+ const renderControls = () => {
245
+ if (hideControls)
246
+ return null;
247
+ return (_jsxs("div", { className: cn("flex flex-col", props.iconMode === "flat" && paddingSize), children: [_jsx("button", { type: "button", onClick: increment, disabled: disabled ||
248
+ (max !== undefined && parseFloat(internalValue) >= max), className: cn(" hover:bg-input-active-stroke/10 disabled:opacity-30 disabled:cursor-not-allowed transition-colors rounded-full text-input-filled-text"), tabIndex: -1, children: _jsx(ChevronUpIcon, { className: controlsSize }) }), _jsx("button", { type: "button", onClick: decrement, disabled: disabled ||
249
+ (min !== undefined && parseFloat(internalValue) <= min), className: cn(" hover:bg-input-active-stroke/10 disabled:opacity-30 disabled:cursor-not-allowed transition-colors rounded-full text-input-filled-text"), tabIndex: -1, children: _jsx(ChevronDownIcon, { className: controlsSize }) })] }));
250
+ };
251
+ return (_jsx(TextInput, Object.assign({}, props, { ref: inputRef, type: "text", inputMode: "decimal", value: displayValue, onChange: handleInputChange, onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown, disabled: disabled, size: size, hasClearIcon: false, endIcon: renderControls(), className: cn(className) })));
252
+ });
253
+ NumberInput.displayName = "NumberInput";
254
+ export default NumberInput;
@@ -0,0 +1,212 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { NumberInput } from "@/index";
3
+ const meta = {
4
+ title: "Components/NumberInput",
5
+ component: NumberInput,
6
+ parameters: {
7
+ layout: "fullscreen",
8
+ },
9
+ tags: ["autodocs"],
10
+ decorators: [
11
+ (Story) => (_jsx("div", { className: "p-5 flex h-screen w-full bg-base-bg2", children: _jsx(Story, {}) })),
12
+ ],
13
+ argTypes: {
14
+ size: {
15
+ control: { type: "radio" },
16
+ options: ["sm", "md", "lg"],
17
+ },
18
+ rounded: {
19
+ control: { type: "radio" },
20
+ options: ["none", "normal", "full"],
21
+ },
22
+ variant: {
23
+ control: { type: "radio" },
24
+ options: ["flat", "outline", "underline"],
25
+ },
26
+ isFloatingLabel: { control: "boolean" },
27
+ fullwidth: { control: "boolean" },
28
+ disabled: { control: "boolean" },
29
+ error: { control: "boolean" },
30
+ required: { control: "boolean" },
31
+ hideControls: { control: "boolean" },
32
+ allowDecimal: { control: "boolean" },
33
+ allowNegative: { control: "boolean" },
34
+ },
35
+ args: {
36
+ label: "Number",
37
+ placeholder: "Enter a number",
38
+ size: "md",
39
+ rounded: "normal",
40
+ variant: "outline",
41
+ isFloatingLabel: true,
42
+ fullwidth: true,
43
+ disabled: false,
44
+ error: false,
45
+ required: true,
46
+ hideControls: false,
47
+ allowDecimal: true,
48
+ allowNegative: true,
49
+ },
50
+ };
51
+ export default meta;
52
+ export const Default = {
53
+ render: (args) => {
54
+ console.log("args ", args);
55
+ const props = Object.assign({}, args);
56
+ return (_jsxs("div", { className: "flex flex-row gap-4 w-full", children: [_jsx(NumberInput, Object.assign({ id: "1" }, props, { size: "lg" })), _jsx(NumberInput, Object.assign({ id: "2" }, props, { size: "md" })), _jsx(NumberInput, Object.assign({ id: "3" }, props, { size: "sm" }))] }));
57
+ },
58
+ };
59
+ export const WithMinMax = {
60
+ args: {
61
+ label: "Age",
62
+ min: 0,
63
+ max: 120,
64
+ helperText: "Age must be between 0 and 120",
65
+ },
66
+ render: (args) => {
67
+ const props = Object.assign({}, args);
68
+ return (_jsxs("div", { className: "flex flex-row gap-4 w-full", children: [_jsx(NumberInput, Object.assign({ id: "1" }, props, { size: "lg" })), _jsx(NumberInput, Object.assign({ id: "2" }, props, { size: "md" })), _jsx(NumberInput, Object.assign({ id: "3" }, props, { size: "sm" }))] }));
69
+ },
70
+ };
71
+ export const WithStep = {
72
+ args: {
73
+ label: "Rating",
74
+ min: 0,
75
+ max: 5,
76
+ step: 0.5,
77
+ defaultValue: 2.5,
78
+ helperText: "Use 0.5 increments",
79
+ },
80
+ render: (args) => {
81
+ const props = Object.assign({}, args);
82
+ return (_jsxs("div", { className: "flex flex-row gap-4 w-full", children: [_jsx(NumberInput, Object.assign({ id: "1" }, props, { size: "lg" })), _jsx(NumberInput, Object.assign({ id: "2" }, props, { size: "md" })), _jsx(NumberInput, Object.assign({ id: "3" }, props, { size: "sm" }))] }));
83
+ },
84
+ };
85
+ export const IntegerOnly = {
86
+ args: {
87
+ label: "Quantity",
88
+ allowDecimal: false,
89
+ min: 1,
90
+ defaultValue: 1,
91
+ helperText: "Integer values only",
92
+ },
93
+ render: (args) => {
94
+ const props = Object.assign({}, args);
95
+ return (_jsxs("div", { className: "flex flex-row gap-4 w-full", children: [_jsx(NumberInput, Object.assign({ id: "1" }, props, { size: "lg" })), _jsx(NumberInput, Object.assign({ id: "2" }, props, { size: "md" })), _jsx(NumberInput, Object.assign({ id: "3" }, props, { size: "sm" }))] }));
96
+ },
97
+ };
98
+ export const ControllWithOutLine = {
99
+ args: {
100
+ label: "Quantity",
101
+ allowDecimal: false,
102
+ iconMode: "flat",
103
+ min: 1,
104
+ defaultValue: 1,
105
+ helperText: "Integer values only",
106
+ },
107
+ render: (args) => {
108
+ const props = Object.assign({}, args);
109
+ return (_jsxs("div", { className: "flex flex-row gap-4 w-full", children: [_jsx(NumberInput, Object.assign({ id: "1" }, props, { size: "lg" })), _jsx(NumberInput, Object.assign({ id: "2" }, props, { size: "md" })), _jsx(NumberInput, Object.assign({ id: "3" }, props, { size: "sm" }))] }));
110
+ },
111
+ };
112
+ export const WithoutControls = {
113
+ args: {
114
+ label: "Custom Number",
115
+ hideControls: true,
116
+ helperText: "No increment/decrement buttons",
117
+ },
118
+ render: (args) => {
119
+ const props = Object.assign({}, args);
120
+ return (_jsxs("div", { className: "flex flex-row gap-4 w-full", children: [_jsx(NumberInput, Object.assign({ id: "1" }, props, { size: "lg" })), _jsx(NumberInput, Object.assign({ id: "2" }, props, { size: "md" })), _jsx(NumberInput, Object.assign({ id: "3" }, props, { size: "sm" }))] }));
121
+ },
122
+ };
123
+ export const ErrorState = {
124
+ args: {
125
+ error: true,
126
+ errorMessage: "Value exceeds maximum allowed",
127
+ defaultValue: 150,
128
+ },
129
+ render: (args) => {
130
+ const props = Object.assign({}, args);
131
+ return (_jsxs("div", { className: "flex flex-row gap-4 w-full", children: [_jsx(NumberInput, Object.assign({ id: "1" }, props, { size: "lg" })), _jsx(NumberInput, Object.assign({ id: "2" }, props, { size: "md" })), _jsx(NumberInput, Object.assign({ id: "3" }, props, { size: "sm" }))] }));
132
+ },
133
+ };
134
+ export const HelperText = {
135
+ args: {
136
+ helperText: "Enter a number between 0 and 100",
137
+ min: 0,
138
+ max: 100,
139
+ },
140
+ render: (args) => {
141
+ const props = Object.assign({}, args);
142
+ return (_jsxs("div", { className: "flex flex-row gap-4 w-full", children: [_jsx(NumberInput, Object.assign({ id: "1" }, props, { size: "lg" })), _jsx(NumberInput, Object.assign({ id: "2" }, props, { size: "md" })), _jsx(NumberInput, Object.assign({ id: "3" }, props, { size: "sm" }))] }));
143
+ },
144
+ };
145
+ export const Disabled = {
146
+ args: {
147
+ disabled: true,
148
+ defaultValue: 50,
149
+ },
150
+ render: (args) => {
151
+ const props = Object.assign({}, args);
152
+ return (_jsxs("div", { className: "flex flex-row gap-4 w-full", children: [_jsx(NumberInput, Object.assign({ id: "1" }, props, { size: "lg" })), _jsx(NumberInput, Object.assign({ id: "2" }, props, { size: "md" })), _jsx(NumberInput, Object.assign({ id: "3" }, props, { size: "sm" }))] }));
153
+ },
154
+ };
155
+ export const FormattedNumber = {
156
+ args: {
157
+ label: "Amount",
158
+ formatDisplay: true,
159
+ precision: 2,
160
+ defaultValue: 1234567.89,
161
+ helperText: "Number with thousand separator",
162
+ },
163
+ render: (args) => {
164
+ const props = Object.assign({}, args);
165
+ return (_jsxs("div", { className: "flex flex-row gap-4 w-full", children: [_jsx(NumberInput, Object.assign({ id: "1" }, props, { size: "lg" })), _jsx(NumberInput, Object.assign({ id: "2" }, props, { size: "md" })), _jsx(NumberInput, Object.assign({ id: "3" }, props, { size: "sm" }))] }));
166
+ },
167
+ };
168
+ export const CurrencyFormat = {
169
+ args: {
170
+ label: "Price",
171
+ formatDisplay: true,
172
+ precision: 2,
173
+ prefix: "$",
174
+ defaultValue: 1230.0,
175
+ min: 0,
176
+ helperText: "Currency format with $ prefix",
177
+ },
178
+ render: (args) => {
179
+ const props = Object.assign({}, args);
180
+ return (_jsxs("div", { className: "flex flex-row gap-4 w-full", children: [_jsx(NumberInput, Object.assign({ id: "1" }, props, { size: "lg" })), _jsx(NumberInput, Object.assign({ id: "2" }, props, { size: "md" })), _jsx(NumberInput, Object.assign({ id: "3" }, props, { size: "sm" }))] }));
181
+ },
182
+ };
183
+ export const CurrencyThailand = {
184
+ args: {
185
+ label: "ราคา",
186
+ formatDisplay: true,
187
+ precision: 2,
188
+ suffix: " ฿",
189
+ defaultValue: 15000.5,
190
+ min: 0,
191
+ helperText: "Thai Baht format",
192
+ },
193
+ render: (args) => {
194
+ const props = Object.assign({}, args);
195
+ return (_jsxs("div", { className: "flex flex-row gap-4 w-full", children: [_jsx(NumberInput, Object.assign({ id: "1" }, props, { size: "lg" })), _jsx(NumberInput, Object.assign({ id: "2" }, props, { size: "md" })), _jsx(NumberInput, Object.assign({ id: "3" }, props, { size: "sm" }))] }));
196
+ },
197
+ };
198
+ export const CustomSeparators = {
199
+ args: {
200
+ label: "European Format",
201
+ formatDisplay: true,
202
+ precision: 2,
203
+ thousandSeparator: ".",
204
+ decimalSeparator: ",",
205
+ defaultValue: 9999.99,
206
+ helperText: "European number format (9.999,99)",
207
+ },
208
+ render: (args) => {
209
+ const props = Object.assign({}, args);
210
+ return (_jsxs("div", { className: "flex flex-row gap-4 w-full", children: [_jsx(NumberInput, Object.assign({ id: "1" }, props, { size: "lg" })), _jsx(NumberInput, Object.assign({ id: "2" }, props, { size: "md" })), _jsx(NumberInput, Object.assign({ id: "3" }, props, { size: "sm" }))] }));
211
+ },
212
+ };
@@ -0,0 +1 @@
1
+ export { NumberInput, default } from "./NumberInput";