@neoptocom/neopto-ui 1.5.2 → 1.5.4
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.cjs +49 -36
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +49 -36
- package/package.json +1 -1
- package/src/components/Autocomplete.tsx +2 -1
- package/src/components/Breadcrumb.docs.mdx +3 -0
- package/src/components/Breadcrumb.stories.tsx +3 -0
- package/src/components/Button.docs.mdx +3 -0
- package/src/components/Button.stories.tsx +3 -0
- package/src/components/Card.docs.mdx +3 -0
- package/src/components/Input.tsx +28 -2
- package/src/stories/Input.stories.tsx +11 -0
package/dist/index.cjs
CHANGED
|
@@ -264,6 +264,39 @@ function Card({
|
|
|
264
264
|
}
|
|
265
265
|
);
|
|
266
266
|
}
|
|
267
|
+
var sizeMap = {
|
|
268
|
+
sm: 16,
|
|
269
|
+
md: 24,
|
|
270
|
+
lg: 36
|
|
271
|
+
};
|
|
272
|
+
function Icon({
|
|
273
|
+
name,
|
|
274
|
+
className = "",
|
|
275
|
+
title,
|
|
276
|
+
size = "md",
|
|
277
|
+
fill = 0
|
|
278
|
+
}) {
|
|
279
|
+
const fontSize = sizeMap[size] ?? sizeMap.md;
|
|
280
|
+
const hasColorClass = /\b(?:text-|fill-|stroke-)\S+/.test(className);
|
|
281
|
+
const style = {
|
|
282
|
+
fontVariationSettings: `'FILL' ${fill}, 'wght' 300, 'GRAD' 0, 'opsz' ${fontSize}`,
|
|
283
|
+
fontSize,
|
|
284
|
+
lineHeight: 1,
|
|
285
|
+
display: "inline-block",
|
|
286
|
+
verticalAlign: "middle",
|
|
287
|
+
...hasColorClass ? {} : { color: "inherit" }
|
|
288
|
+
};
|
|
289
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
290
|
+
"span",
|
|
291
|
+
{
|
|
292
|
+
className: `material-symbols-rounded rounded ${className}`,
|
|
293
|
+
style,
|
|
294
|
+
"aria-hidden": title ? void 0 : true,
|
|
295
|
+
title,
|
|
296
|
+
children: name
|
|
297
|
+
}
|
|
298
|
+
);
|
|
299
|
+
}
|
|
267
300
|
var Input = React3__namespace.forwardRef(
|
|
268
301
|
({
|
|
269
302
|
className,
|
|
@@ -273,14 +306,17 @@ var Input = React3__namespace.forwardRef(
|
|
|
273
306
|
fieldsetProps,
|
|
274
307
|
legendProps,
|
|
275
308
|
error = false,
|
|
309
|
+
icon,
|
|
276
310
|
...props
|
|
277
311
|
}, ref) => {
|
|
278
312
|
const isInlineVariant = variant === "inline";
|
|
279
313
|
const shouldUseInlineStyles = isInlineVariant || Boolean(label);
|
|
280
314
|
const isError = error && !disabled;
|
|
315
|
+
const hasIcon = Boolean(icon);
|
|
281
316
|
const inputClasses = [
|
|
282
317
|
"w-full bg-transparent outline-none transition-colors",
|
|
283
|
-
shouldUseInlineStyles ? "h-9" : "h-12
|
|
318
|
+
shouldUseInlineStyles ? "h-9" : "h-12 rounded-full",
|
|
319
|
+
shouldUseInlineStyles ? hasIcon ? "pr-8" : "" : hasIcon ? "px-4 pr-10" : "px-4",
|
|
284
320
|
"font-['Poppins'] text-sm placeholder:text-[var(--muted-fg)]"
|
|
285
321
|
];
|
|
286
322
|
if (!shouldUseInlineStyles) {
|
|
@@ -307,6 +343,12 @@ var Input = React3__namespace.forwardRef(
|
|
|
307
343
|
const inputClassName = inputClasses.join(" ");
|
|
308
344
|
const inputElement = /* @__PURE__ */ jsxRuntime.jsx("input", { ref, disabled, className: inputClassName, ...props });
|
|
309
345
|
if (!label) {
|
|
346
|
+
if (hasIcon) {
|
|
347
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
348
|
+
inputElement,
|
|
349
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-4 top-1/2 -translate-y-1/2 pointer-events-none", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: icon, className: "text-[var(--muted-fg)] opacity-50" }) })
|
|
350
|
+
] });
|
|
351
|
+
}
|
|
310
352
|
return inputElement;
|
|
311
353
|
}
|
|
312
354
|
const { className: fieldsetClassNameProp = "", ...restFieldsetProps } = fieldsetProps ?? {};
|
|
@@ -338,7 +380,10 @@ var Input = React3__namespace.forwardRef(
|
|
|
338
380
|
children: label
|
|
339
381
|
}
|
|
340
382
|
),
|
|
341
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex pl-5 pr-3 pb-1 h-full", children: /* @__PURE__ */ jsxRuntime.
|
|
383
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex pl-5 pr-3 pb-1 h-full", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full relative", children: [
|
|
384
|
+
inputElement,
|
|
385
|
+
hasIcon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-1 top-1/2 -translate-y-1/2 pointer-events-none", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: icon, className: "text-[var(--muted-fg)] opacity-50" }) })
|
|
386
|
+
] }) })
|
|
342
387
|
]
|
|
343
388
|
}
|
|
344
389
|
);
|
|
@@ -625,39 +670,6 @@ function Skeleton({ className = "", rounded = "md", ...props }) {
|
|
|
625
670
|
}
|
|
626
671
|
);
|
|
627
672
|
}
|
|
628
|
-
var sizeMap = {
|
|
629
|
-
sm: 16,
|
|
630
|
-
md: 24,
|
|
631
|
-
lg: 36
|
|
632
|
-
};
|
|
633
|
-
function Icon({
|
|
634
|
-
name,
|
|
635
|
-
className = "",
|
|
636
|
-
title,
|
|
637
|
-
size = "md",
|
|
638
|
-
fill = 0
|
|
639
|
-
}) {
|
|
640
|
-
const fontSize = sizeMap[size] ?? sizeMap.md;
|
|
641
|
-
const hasColorClass = /\b(?:text-|fill-|stroke-)\S+/.test(className);
|
|
642
|
-
const style = {
|
|
643
|
-
fontVariationSettings: `'FILL' ${fill}, 'wght' 300, 'GRAD' 0, 'opsz' ${fontSize}`,
|
|
644
|
-
fontSize,
|
|
645
|
-
lineHeight: 1,
|
|
646
|
-
display: "inline-block",
|
|
647
|
-
verticalAlign: "middle",
|
|
648
|
-
...hasColorClass ? {} : { color: "inherit" }
|
|
649
|
-
};
|
|
650
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
651
|
-
"span",
|
|
652
|
-
{
|
|
653
|
-
className: `material-symbols-rounded rounded ${className}`,
|
|
654
|
-
style,
|
|
655
|
-
"aria-hidden": title ? void 0 : true,
|
|
656
|
-
title,
|
|
657
|
-
children: name
|
|
658
|
-
}
|
|
659
|
-
);
|
|
660
|
-
}
|
|
661
673
|
function getIconButtonClasses(variant = "ghost", size = "md", className) {
|
|
662
674
|
const base = "cursor-pointer flex items-center justify-center rounded-full flex-shrink-0 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-cyan-500/40 disabled:cursor-not-allowed disabled:opacity-50";
|
|
663
675
|
const variants = {
|
|
@@ -831,7 +843,7 @@ function Autocomplete({
|
|
|
831
843
|
"fieldset",
|
|
832
844
|
{
|
|
833
845
|
className: [
|
|
834
|
-
"w-full min-w-0 rounded-full border bg-[var(--surface)] transition-colors h-
|
|
846
|
+
"w-full min-w-0 rounded-full border bg-[var(--surface)] transition-colors h-13",
|
|
835
847
|
"border-[var(--border)] focus-within:border-[var(--color-brand)]",
|
|
836
848
|
disabled ? "opacity-60 cursor-not-allowed" : ""
|
|
837
849
|
].join(" "),
|
|
@@ -885,6 +897,7 @@ function Autocomplete({
|
|
|
885
897
|
onClick: selectedOption && !open ? handleClear : () => setOpen((s) => !s),
|
|
886
898
|
disabled,
|
|
887
899
|
"aria-label": selectedOption && !open ? "Clear" : open ? "Collapse" : "Expand",
|
|
900
|
+
className: "absolute right-0 top-[-30%]",
|
|
888
901
|
iconClassName: [
|
|
889
902
|
"transition-transform duration-300 text-[var(--muted-fg)]",
|
|
890
903
|
open ? "rotate-180 text-[var(--color-brand)]" : ""
|
package/dist/index.d.cts
CHANGED
|
@@ -70,6 +70,8 @@ type InputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"> & {
|
|
|
70
70
|
legendProps?: React.HTMLAttributes<HTMLLegendElement>;
|
|
71
71
|
/** Flag to visually mark the input as errored */
|
|
72
72
|
error?: boolean;
|
|
73
|
+
/** Optional icon name to display on the inner right of the input */
|
|
74
|
+
icon?: string;
|
|
73
75
|
};
|
|
74
76
|
declare const Input: React.ForwardRefExoticComponent<Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"> & {
|
|
75
77
|
/** Input visual variant */
|
|
@@ -82,6 +84,8 @@ declare const Input: React.ForwardRefExoticComponent<Omit<React.InputHTMLAttribu
|
|
|
82
84
|
legendProps?: React.HTMLAttributes<HTMLLegendElement>;
|
|
83
85
|
/** Flag to visually mark the input as errored */
|
|
84
86
|
error?: boolean;
|
|
87
|
+
/** Optional icon name to display on the inner right of the input */
|
|
88
|
+
icon?: string;
|
|
85
89
|
} & React.RefAttributes<HTMLInputElement>>;
|
|
86
90
|
|
|
87
91
|
type TextareaProps = Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'size'> & {
|
package/dist/index.d.ts
CHANGED
|
@@ -70,6 +70,8 @@ type InputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"> & {
|
|
|
70
70
|
legendProps?: React.HTMLAttributes<HTMLLegendElement>;
|
|
71
71
|
/** Flag to visually mark the input as errored */
|
|
72
72
|
error?: boolean;
|
|
73
|
+
/** Optional icon name to display on the inner right of the input */
|
|
74
|
+
icon?: string;
|
|
73
75
|
};
|
|
74
76
|
declare const Input: React.ForwardRefExoticComponent<Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"> & {
|
|
75
77
|
/** Input visual variant */
|
|
@@ -82,6 +84,8 @@ declare const Input: React.ForwardRefExoticComponent<Omit<React.InputHTMLAttribu
|
|
|
82
84
|
legendProps?: React.HTMLAttributes<HTMLLegendElement>;
|
|
83
85
|
/** Flag to visually mark the input as errored */
|
|
84
86
|
error?: boolean;
|
|
87
|
+
/** Optional icon name to display on the inner right of the input */
|
|
88
|
+
icon?: string;
|
|
85
89
|
} & React.RefAttributes<HTMLInputElement>>;
|
|
86
90
|
|
|
87
91
|
type TextareaProps = Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'size'> & {
|
package/dist/index.js
CHANGED
|
@@ -243,6 +243,39 @@ function Card({
|
|
|
243
243
|
}
|
|
244
244
|
);
|
|
245
245
|
}
|
|
246
|
+
var sizeMap = {
|
|
247
|
+
sm: 16,
|
|
248
|
+
md: 24,
|
|
249
|
+
lg: 36
|
|
250
|
+
};
|
|
251
|
+
function Icon({
|
|
252
|
+
name,
|
|
253
|
+
className = "",
|
|
254
|
+
title,
|
|
255
|
+
size = "md",
|
|
256
|
+
fill = 0
|
|
257
|
+
}) {
|
|
258
|
+
const fontSize = sizeMap[size] ?? sizeMap.md;
|
|
259
|
+
const hasColorClass = /\b(?:text-|fill-|stroke-)\S+/.test(className);
|
|
260
|
+
const style = {
|
|
261
|
+
fontVariationSettings: `'FILL' ${fill}, 'wght' 300, 'GRAD' 0, 'opsz' ${fontSize}`,
|
|
262
|
+
fontSize,
|
|
263
|
+
lineHeight: 1,
|
|
264
|
+
display: "inline-block",
|
|
265
|
+
verticalAlign: "middle",
|
|
266
|
+
...hasColorClass ? {} : { color: "inherit" }
|
|
267
|
+
};
|
|
268
|
+
return /* @__PURE__ */ jsx(
|
|
269
|
+
"span",
|
|
270
|
+
{
|
|
271
|
+
className: `material-symbols-rounded rounded ${className}`,
|
|
272
|
+
style,
|
|
273
|
+
"aria-hidden": title ? void 0 : true,
|
|
274
|
+
title,
|
|
275
|
+
children: name
|
|
276
|
+
}
|
|
277
|
+
);
|
|
278
|
+
}
|
|
246
279
|
var Input = React3.forwardRef(
|
|
247
280
|
({
|
|
248
281
|
className,
|
|
@@ -252,14 +285,17 @@ var Input = React3.forwardRef(
|
|
|
252
285
|
fieldsetProps,
|
|
253
286
|
legendProps,
|
|
254
287
|
error = false,
|
|
288
|
+
icon,
|
|
255
289
|
...props
|
|
256
290
|
}, ref) => {
|
|
257
291
|
const isInlineVariant = variant === "inline";
|
|
258
292
|
const shouldUseInlineStyles = isInlineVariant || Boolean(label);
|
|
259
293
|
const isError = error && !disabled;
|
|
294
|
+
const hasIcon = Boolean(icon);
|
|
260
295
|
const inputClasses = [
|
|
261
296
|
"w-full bg-transparent outline-none transition-colors",
|
|
262
|
-
shouldUseInlineStyles ? "h-9" : "h-12
|
|
297
|
+
shouldUseInlineStyles ? "h-9" : "h-12 rounded-full",
|
|
298
|
+
shouldUseInlineStyles ? hasIcon ? "pr-8" : "" : hasIcon ? "px-4 pr-10" : "px-4",
|
|
263
299
|
"font-['Poppins'] text-sm placeholder:text-[var(--muted-fg)]"
|
|
264
300
|
];
|
|
265
301
|
if (!shouldUseInlineStyles) {
|
|
@@ -286,6 +322,12 @@ var Input = React3.forwardRef(
|
|
|
286
322
|
const inputClassName = inputClasses.join(" ");
|
|
287
323
|
const inputElement = /* @__PURE__ */ jsx("input", { ref, disabled, className: inputClassName, ...props });
|
|
288
324
|
if (!label) {
|
|
325
|
+
if (hasIcon) {
|
|
326
|
+
return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
327
|
+
inputElement,
|
|
328
|
+
/* @__PURE__ */ jsx("div", { className: "absolute right-4 top-1/2 -translate-y-1/2 pointer-events-none", children: /* @__PURE__ */ jsx(Icon, { name: icon, className: "text-[var(--muted-fg)] opacity-50" }) })
|
|
329
|
+
] });
|
|
330
|
+
}
|
|
289
331
|
return inputElement;
|
|
290
332
|
}
|
|
291
333
|
const { className: fieldsetClassNameProp = "", ...restFieldsetProps } = fieldsetProps ?? {};
|
|
@@ -317,7 +359,10 @@ var Input = React3.forwardRef(
|
|
|
317
359
|
children: label
|
|
318
360
|
}
|
|
319
361
|
),
|
|
320
|
-
/* @__PURE__ */ jsx("div", { className: "relative flex pl-5 pr-3 pb-1 h-full", children: /* @__PURE__ */
|
|
362
|
+
/* @__PURE__ */ jsx("div", { className: "relative flex pl-5 pr-3 pb-1 h-full", children: /* @__PURE__ */ jsxs("div", { className: "flex w-full relative", children: [
|
|
363
|
+
inputElement,
|
|
364
|
+
hasIcon && /* @__PURE__ */ jsx("div", { className: "absolute right-1 top-1/2 -translate-y-1/2 pointer-events-none", children: /* @__PURE__ */ jsx(Icon, { name: icon, className: "text-[var(--muted-fg)] opacity-50" }) })
|
|
365
|
+
] }) })
|
|
321
366
|
]
|
|
322
367
|
}
|
|
323
368
|
);
|
|
@@ -604,39 +649,6 @@ function Skeleton({ className = "", rounded = "md", ...props }) {
|
|
|
604
649
|
}
|
|
605
650
|
);
|
|
606
651
|
}
|
|
607
|
-
var sizeMap = {
|
|
608
|
-
sm: 16,
|
|
609
|
-
md: 24,
|
|
610
|
-
lg: 36
|
|
611
|
-
};
|
|
612
|
-
function Icon({
|
|
613
|
-
name,
|
|
614
|
-
className = "",
|
|
615
|
-
title,
|
|
616
|
-
size = "md",
|
|
617
|
-
fill = 0
|
|
618
|
-
}) {
|
|
619
|
-
const fontSize = sizeMap[size] ?? sizeMap.md;
|
|
620
|
-
const hasColorClass = /\b(?:text-|fill-|stroke-)\S+/.test(className);
|
|
621
|
-
const style = {
|
|
622
|
-
fontVariationSettings: `'FILL' ${fill}, 'wght' 300, 'GRAD' 0, 'opsz' ${fontSize}`,
|
|
623
|
-
fontSize,
|
|
624
|
-
lineHeight: 1,
|
|
625
|
-
display: "inline-block",
|
|
626
|
-
verticalAlign: "middle",
|
|
627
|
-
...hasColorClass ? {} : { color: "inherit" }
|
|
628
|
-
};
|
|
629
|
-
return /* @__PURE__ */ jsx(
|
|
630
|
-
"span",
|
|
631
|
-
{
|
|
632
|
-
className: `material-symbols-rounded rounded ${className}`,
|
|
633
|
-
style,
|
|
634
|
-
"aria-hidden": title ? void 0 : true,
|
|
635
|
-
title,
|
|
636
|
-
children: name
|
|
637
|
-
}
|
|
638
|
-
);
|
|
639
|
-
}
|
|
640
652
|
function getIconButtonClasses(variant = "ghost", size = "md", className) {
|
|
641
653
|
const base = "cursor-pointer flex items-center justify-center rounded-full flex-shrink-0 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-cyan-500/40 disabled:cursor-not-allowed disabled:opacity-50";
|
|
642
654
|
const variants = {
|
|
@@ -810,7 +822,7 @@ function Autocomplete({
|
|
|
810
822
|
"fieldset",
|
|
811
823
|
{
|
|
812
824
|
className: [
|
|
813
|
-
"w-full min-w-0 rounded-full border bg-[var(--surface)] transition-colors h-
|
|
825
|
+
"w-full min-w-0 rounded-full border bg-[var(--surface)] transition-colors h-13",
|
|
814
826
|
"border-[var(--border)] focus-within:border-[var(--color-brand)]",
|
|
815
827
|
disabled ? "opacity-60 cursor-not-allowed" : ""
|
|
816
828
|
].join(" "),
|
|
@@ -864,6 +876,7 @@ function Autocomplete({
|
|
|
864
876
|
onClick: selectedOption && !open ? handleClear : () => setOpen((s) => !s),
|
|
865
877
|
disabled,
|
|
866
878
|
"aria-label": selectedOption && !open ? "Clear" : open ? "Collapse" : "Expand",
|
|
879
|
+
className: "absolute right-0 top-[-30%]",
|
|
867
880
|
iconClassName: [
|
|
868
881
|
"transition-transform duration-300 text-[var(--muted-fg)]",
|
|
869
882
|
open ? "rotate-180 text-[var(--color-brand)]" : ""
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neoptocom/neopto-ui",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A modern React component library built with Tailwind CSS v4 and TypeScript. Features dark mode, design tokens, and comprehensive Storybook documentation. Requires Tailwind v4+.",
|
|
6
6
|
"keywords": [
|
|
@@ -167,7 +167,7 @@ export default function Autocomplete({
|
|
|
167
167
|
>
|
|
168
168
|
<fieldset
|
|
169
169
|
className={[
|
|
170
|
-
"w-full min-w-0 rounded-full border bg-[var(--surface)] transition-colors h-
|
|
170
|
+
"w-full min-w-0 rounded-full border bg-[var(--surface)] transition-colors h-13",
|
|
171
171
|
"border-[var(--border)] focus-within:border-[var(--color-brand)]",
|
|
172
172
|
disabled ? "opacity-60 cursor-not-allowed" : ""
|
|
173
173
|
].join(" ")}
|
|
@@ -222,6 +222,7 @@ export default function Autocomplete({
|
|
|
222
222
|
}
|
|
223
223
|
disabled={disabled}
|
|
224
224
|
aria-label={selectedOption && !open ? "Clear" : open ? "Collapse" : "Expand"}
|
|
225
|
+
className="absolute right-0 top-[-30%]"
|
|
225
226
|
iconClassName={[
|
|
226
227
|
"transition-transform duration-300 text-[var(--muted-fg)]",
|
|
227
228
|
open ? "rotate-180 text-[var(--color-brand)]" : ""
|
package/src/components/Input.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import Icon from "./Icon";
|
|
2
3
|
|
|
3
4
|
export type InputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"> & {
|
|
4
5
|
/** Input visual variant */
|
|
@@ -11,6 +12,8 @@ export type InputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, "size
|
|
|
11
12
|
legendProps?: React.HTMLAttributes<HTMLLegendElement>;
|
|
12
13
|
/** Flag to visually mark the input as errored */
|
|
13
14
|
error?: boolean;
|
|
15
|
+
/** Optional icon name to display on the inner right of the input */
|
|
16
|
+
icon?: string;
|
|
14
17
|
};
|
|
15
18
|
|
|
16
19
|
export const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
@@ -23,6 +26,7 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
23
26
|
fieldsetProps,
|
|
24
27
|
legendProps,
|
|
25
28
|
error = false,
|
|
29
|
+
icon,
|
|
26
30
|
...props
|
|
27
31
|
},
|
|
28
32
|
ref
|
|
@@ -30,10 +34,14 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
30
34
|
const isInlineVariant = variant === "inline";
|
|
31
35
|
const shouldUseInlineStyles = isInlineVariant || Boolean(label);
|
|
32
36
|
const isError = error && !disabled;
|
|
37
|
+
const hasIcon = Boolean(icon);
|
|
33
38
|
|
|
34
39
|
const inputClasses: string[] = [
|
|
35
40
|
"w-full bg-transparent outline-none transition-colors",
|
|
36
|
-
shouldUseInlineStyles ? "h-9" : "h-12
|
|
41
|
+
shouldUseInlineStyles ? "h-9" : "h-12 rounded-full",
|
|
42
|
+
shouldUseInlineStyles
|
|
43
|
+
? (hasIcon ? "pr-8" : "")
|
|
44
|
+
: (hasIcon ? "px-4 pr-10" : "px-4"),
|
|
37
45
|
"font-['Poppins'] text-sm placeholder:text-[var(--muted-fg)]"
|
|
38
46
|
];
|
|
39
47
|
|
|
@@ -67,7 +75,18 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
67
75
|
<input ref={ref} disabled={disabled} className={inputClassName} {...props} />
|
|
68
76
|
);
|
|
69
77
|
|
|
78
|
+
// Standalone input (no label)
|
|
70
79
|
if (!label) {
|
|
80
|
+
if (hasIcon) {
|
|
81
|
+
return (
|
|
82
|
+
<div className="relative">
|
|
83
|
+
{inputElement}
|
|
84
|
+
<div className="absolute right-4 top-1/2 -translate-y-1/2 pointer-events-none">
|
|
85
|
+
<Icon name={icon!} className="text-[var(--muted-fg)] opacity-50" />
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
71
90
|
return inputElement;
|
|
72
91
|
}
|
|
73
92
|
|
|
@@ -113,7 +132,14 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
113
132
|
{label}
|
|
114
133
|
</legend>
|
|
115
134
|
<div className="relative flex pl-5 pr-3 pb-1 h-full">
|
|
116
|
-
<div className="flex w-full">
|
|
135
|
+
<div className="flex w-full relative">
|
|
136
|
+
{inputElement}
|
|
137
|
+
{hasIcon && (
|
|
138
|
+
<div className="absolute right-1 top-1/2 -translate-y-1/2 pointer-events-none">
|
|
139
|
+
<Icon name={icon!} className="text-[var(--muted-fg)] opacity-50" />
|
|
140
|
+
</div>
|
|
141
|
+
)}
|
|
142
|
+
</div>
|
|
117
143
|
</div>
|
|
118
144
|
</fieldset>
|
|
119
145
|
);
|
|
@@ -73,3 +73,14 @@ export const Error: Story = {
|
|
|
73
73
|
</div>
|
|
74
74
|
)
|
|
75
75
|
};
|
|
76
|
+
|
|
77
|
+
export const WithIcon: Story = {
|
|
78
|
+
render: () => (
|
|
79
|
+
<div className="flex flex-col gap-4 w-96">
|
|
80
|
+
<Input variant="inline" icon="search" placeholder="Search..." />
|
|
81
|
+
<Input icon="email" type="email" placeholder="Email" />
|
|
82
|
+
<Input label="Username" icon="person" placeholder="johndoe" />
|
|
83
|
+
<Input label="Password" icon="lock" type="password" placeholder="Required field" error />
|
|
84
|
+
</div>
|
|
85
|
+
)
|
|
86
|
+
};
|