@neoptocom/neopto-ui 1.5.3 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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'> & {
@@ -388,4 +392,51 @@ interface BreadcrumbProps {
388
392
  */
389
393
  declare const Breadcrumb: React__default.FC<BreadcrumbProps>;
390
394
 
391
- export { AgentButton, type AgentButtonProps, AnimatedBgCircle, AnimatedBgRectangle, AppBackground, type AppBackgroundProps, Autocomplete, type AutocompleteOption, type AutocompleteProps, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, BackgroundBlur, type BackgroundBlurProps, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, type ButtonProps, Card, type CardProps, Chip, type ChipProps, Counter, type CounterProps, Icon, IconButton, type IconButtonProps, type IconProps, Input, type InputProps, MessageBubble, type MessageBubbleProps, Modal, type ModalProps, Search, type SearchOption, type SearchProps, Separator, type SeparatorProps, Skeleton, type SkeletonProps, Textarea, type TextareaProps, Typo, type TypoProps, type TypoVariant, type TypoWeight, index as assets };
395
+ type DateInputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, "value" | "onChange" | "type"> & {
396
+ /** Label text displayed above the input */
397
+ label?: string;
398
+ /** Current date value */
399
+ value?: Date | null;
400
+ /** Callback when date changes */
401
+ onChange: (date: Date) => void;
402
+ /** Flag to visually mark the input as errored */
403
+ error?: boolean;
404
+ /** Minimum selectable date */
405
+ minDate?: Date;
406
+ /** Maximum selectable date */
407
+ maxDate?: Date;
408
+ /** Placeholder text (default: "00/00/0000") */
409
+ placeholder?: string;
410
+ };
411
+ declare const DateInput: React.ForwardRefExoticComponent<Omit<React.InputHTMLAttributes<HTMLInputElement>, "onChange" | "type" | "value"> & {
412
+ /** Label text displayed above the input */
413
+ label?: string;
414
+ /** Current date value */
415
+ value?: Date | null;
416
+ /** Callback when date changes */
417
+ onChange: (date: Date) => void;
418
+ /** Flag to visually mark the input as errored */
419
+ error?: boolean;
420
+ /** Minimum selectable date */
421
+ minDate?: Date;
422
+ /** Maximum selectable date */
423
+ maxDate?: Date;
424
+ /** Placeholder text (default: "00/00/0000") */
425
+ placeholder?: string;
426
+ } & React.RefAttributes<HTMLInputElement>>;
427
+
428
+ type CalendarProps = {
429
+ /** Currently selected date */
430
+ selectedDate?: Date;
431
+ /** Callback when a date is selected */
432
+ onDateSelect: (date: Date) => void;
433
+ /** Today's date (for highlighting) */
434
+ today?: Date;
435
+ /** Minimum selectable date */
436
+ minDate?: Date;
437
+ /** Maximum selectable date */
438
+ maxDate?: Date;
439
+ };
440
+ declare function Calendar({ selectedDate, onDateSelect, today, minDate, maxDate, }: CalendarProps): react_jsx_runtime.JSX.Element;
441
+
442
+ export { AgentButton, type AgentButtonProps, AnimatedBgCircle, AnimatedBgRectangle, AppBackground, type AppBackgroundProps, Autocomplete, type AutocompleteOption, type AutocompleteProps, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, BackgroundBlur, type BackgroundBlurProps, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, type ButtonProps, Calendar, type CalendarProps, Card, type CardProps, Chip, type ChipProps, Counter, type CounterProps, DateInput, type DateInputProps, Icon, IconButton, type IconButtonProps, type IconProps, Input, type InputProps, MessageBubble, type MessageBubbleProps, Modal, type ModalProps, Search, type SearchOption, type SearchProps, Separator, type SeparatorProps, Skeleton, type SkeletonProps, Textarea, type TextareaProps, Typo, type TypoProps, type TypoVariant, type TypoWeight, index as assets };
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'> & {
@@ -388,4 +392,51 @@ interface BreadcrumbProps {
388
392
  */
389
393
  declare const Breadcrumb: React__default.FC<BreadcrumbProps>;
390
394
 
391
- export { AgentButton, type AgentButtonProps, AnimatedBgCircle, AnimatedBgRectangle, AppBackground, type AppBackgroundProps, Autocomplete, type AutocompleteOption, type AutocompleteProps, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, BackgroundBlur, type BackgroundBlurProps, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, type ButtonProps, Card, type CardProps, Chip, type ChipProps, Counter, type CounterProps, Icon, IconButton, type IconButtonProps, type IconProps, Input, type InputProps, MessageBubble, type MessageBubbleProps, Modal, type ModalProps, Search, type SearchOption, type SearchProps, Separator, type SeparatorProps, Skeleton, type SkeletonProps, Textarea, type TextareaProps, Typo, type TypoProps, type TypoVariant, type TypoWeight, index as assets };
395
+ type DateInputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, "value" | "onChange" | "type"> & {
396
+ /** Label text displayed above the input */
397
+ label?: string;
398
+ /** Current date value */
399
+ value?: Date | null;
400
+ /** Callback when date changes */
401
+ onChange: (date: Date) => void;
402
+ /** Flag to visually mark the input as errored */
403
+ error?: boolean;
404
+ /** Minimum selectable date */
405
+ minDate?: Date;
406
+ /** Maximum selectable date */
407
+ maxDate?: Date;
408
+ /** Placeholder text (default: "00/00/0000") */
409
+ placeholder?: string;
410
+ };
411
+ declare const DateInput: React.ForwardRefExoticComponent<Omit<React.InputHTMLAttributes<HTMLInputElement>, "onChange" | "type" | "value"> & {
412
+ /** Label text displayed above the input */
413
+ label?: string;
414
+ /** Current date value */
415
+ value?: Date | null;
416
+ /** Callback when date changes */
417
+ onChange: (date: Date) => void;
418
+ /** Flag to visually mark the input as errored */
419
+ error?: boolean;
420
+ /** Minimum selectable date */
421
+ minDate?: Date;
422
+ /** Maximum selectable date */
423
+ maxDate?: Date;
424
+ /** Placeholder text (default: "00/00/0000") */
425
+ placeholder?: string;
426
+ } & React.RefAttributes<HTMLInputElement>>;
427
+
428
+ type CalendarProps = {
429
+ /** Currently selected date */
430
+ selectedDate?: Date;
431
+ /** Callback when a date is selected */
432
+ onDateSelect: (date: Date) => void;
433
+ /** Today's date (for highlighting) */
434
+ today?: Date;
435
+ /** Minimum selectable date */
436
+ minDate?: Date;
437
+ /** Maximum selectable date */
438
+ maxDate?: Date;
439
+ };
440
+ declare function Calendar({ selectedDate, onDateSelect, today, minDate, maxDate, }: CalendarProps): react_jsx_runtime.JSX.Element;
441
+
442
+ export { AgentButton, type AgentButtonProps, AnimatedBgCircle, AnimatedBgRectangle, AppBackground, type AppBackgroundProps, Autocomplete, type AutocompleteOption, type AutocompleteProps, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, BackgroundBlur, type BackgroundBlurProps, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, type ButtonProps, Calendar, type CalendarProps, Card, type CardProps, Chip, type ChipProps, Counter, type CounterProps, DateInput, type DateInputProps, Icon, IconButton, type IconButtonProps, type IconProps, Input, type InputProps, MessageBubble, type MessageBubbleProps, Modal, type ModalProps, Search, type SearchOption, type SearchProps, Separator, type SeparatorProps, Skeleton, type SkeletonProps, Textarea, type TextareaProps, Typo, type TypoProps, type TypoVariant, type TypoWeight, index as assets };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import * as React3 from 'react';
2
+ import * as React11 from 'react';
3
3
  import { useState, useEffect, useMemo, useId, useRef, useCallback } from 'react';
4
4
  import { createPortal } from 'react-dom';
5
5
 
@@ -243,7 +243,40 @@ function Card({
243
243
  }
244
244
  );
245
245
  }
246
- var Input = React3.forwardRef(
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
+ }
279
+ var Input = React11.forwardRef(
247
280
  ({
248
281
  className,
249
282
  disabled,
@@ -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 px-4 rounded-full",
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,14 +359,17 @@ 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__ */ jsx("div", { className: "flex w-full", children: inputElement }) })
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
  );
324
369
  }
325
370
  );
326
371
  Input.displayName = "Input";
327
- var Textarea = React3.forwardRef(
372
+ var Textarea = React11.forwardRef(
328
373
  ({ className, disabled, variant = "default", ...props }, ref) => {
329
374
  const isInline = variant === "inline";
330
375
  return /* @__PURE__ */ jsx(
@@ -353,7 +398,7 @@ var Textarea = React3.forwardRef(
353
398
  );
354
399
  Textarea.displayName = "Textarea";
355
400
  function useIsomorphicLayoutEffect(effect, deps) {
356
- const useEffectHook = typeof window !== "undefined" ? React3.useLayoutEffect : React3.useEffect;
401
+ const useEffectHook = typeof window !== "undefined" ? React11.useLayoutEffect : React11.useEffect;
357
402
  useEffectHook(effect, deps);
358
403
  }
359
404
  function Modal({
@@ -365,9 +410,9 @@ function Modal({
365
410
  zIndex = 50,
366
411
  showDecorations = true
367
412
  }) {
368
- const [mounted, setMounted] = React3.useState(false);
369
- const [isDark, setIsDark] = React3.useState(false);
370
- React3.useEffect(() => {
413
+ const [mounted, setMounted] = React11.useState(false);
414
+ const [isDark, setIsDark] = React11.useState(false);
415
+ React11.useEffect(() => {
371
416
  const checkDarkMode = () => {
372
417
  const hasDarkClass = document.documentElement.classList.contains("dark") || document.body.classList.contains("dark") || document.querySelector(".dark") !== null;
373
418
  setIsDark(hasDarkClass);
@@ -390,7 +435,7 @@ function Modal({
390
435
  document.body.style.overflow = original;
391
436
  };
392
437
  }, [open]);
393
- React3.useEffect(() => {
438
+ React11.useEffect(() => {
394
439
  if (!open) return;
395
440
  const onKey = (e) => {
396
441
  if (e.key === "Escape") onClose?.();
@@ -550,7 +595,7 @@ function AvatarGroup({
550
595
  overlapPx = 8,
551
596
  withRings = true
552
597
  }) {
553
- const avatars = React3.Children.toArray(children);
598
+ const avatars = React11.Children.toArray(children);
554
599
  const displayAvatars = typeof max === "number" ? avatars.slice(0, max) : avatars;
555
600
  const extraCount = typeof max === "number" && avatars.length > max ? avatars.length - max : 0;
556
601
  return /* @__PURE__ */ jsxs("div", { className: ["flex items-center", className].filter(Boolean).join(" "), children: [
@@ -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 = {
@@ -651,7 +663,7 @@ function getIconButtonClasses(variant = "ghost", size = "md", className) {
651
663
  };
652
664
  return [base, variants[variant], sizes[size], className].filter(Boolean).join(" ");
653
665
  }
654
- var IconButton = React3.forwardRef(
666
+ var IconButton = React11.forwardRef(
655
667
  ({
656
668
  variant,
657
669
  size,
@@ -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-13",
825
+ "w-full min-w-0 rounded-full border bg-[var(--surface)] transition-colors h-14",
814
826
  "border-[var(--border)] focus-within:border-[var(--color-brand)]",
815
827
  disabled ? "opacity-60 cursor-not-allowed" : ""
816
828
  ].join(" "),
@@ -1025,7 +1037,7 @@ function Search({
1025
1037
  const el = list.children[idx];
1026
1038
  el?.scrollIntoView({ block: "nearest" });
1027
1039
  }
1028
- React3.useEffect(() => {
1040
+ React11.useEffect(() => {
1029
1041
  return () => {
1030
1042
  if (searchTimeoutRef.current) {
1031
1043
  clearTimeout(searchTimeoutRef.current);
@@ -1132,7 +1144,7 @@ function getButtonClasses(variant = "primary", size = "md", fullWidth, className
1132
1144
  className
1133
1145
  ].filter(Boolean).join(" ");
1134
1146
  }
1135
- var Button = React3.forwardRef(
1147
+ var Button = React11.forwardRef(
1136
1148
  ({ variant, size, fullWidth, className, children, icon, ...props }, ref) => {
1137
1149
  return /* @__PURE__ */ jsx(
1138
1150
  "button",
@@ -1204,8 +1216,8 @@ function Counter({
1204
1216
  className = "",
1205
1217
  ...props
1206
1218
  }) {
1207
- const [count, setCount] = React3.useState(value);
1208
- React3.useEffect(() => {
1219
+ const [count, setCount] = React11.useState(value);
1220
+ React11.useEffect(() => {
1209
1221
  setCount(value);
1210
1222
  }, [value]);
1211
1223
  const handleIncrement = () => {
@@ -1438,7 +1450,7 @@ var AgentButton = ({
1438
1450
  );
1439
1451
  };
1440
1452
  var AgentButton_default = AgentButton;
1441
- var MessageBubble = React3.forwardRef(
1453
+ var MessageBubble = React11.forwardRef(
1442
1454
  ({ direction, color, children, className, ...props }, ref) => {
1443
1455
  const borderRadiusClass = direction === "left" ? "[border-radius:16px_16px_16px_2px]" : direction === "right" ? "[border-radius:16px_16px_2px_16px]" : "rounded-2xl";
1444
1456
  const backgroundColor = color || "var(--muted)";
@@ -1516,5 +1528,304 @@ var Breadcrumb = ({
1516
1528
  ] }, index);
1517
1529
  }) }) });
1518
1530
  };
1531
+ var DAYS_OF_WEEK = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
1532
+ var MONTHS = [
1533
+ "January",
1534
+ "February",
1535
+ "March",
1536
+ "April",
1537
+ "May",
1538
+ "June",
1539
+ "July",
1540
+ "August",
1541
+ "September",
1542
+ "October",
1543
+ "November",
1544
+ "December"
1545
+ ];
1546
+ function isSameDay(date1, date2) {
1547
+ return date1.getDate() === date2.getDate() && date1.getMonth() === date2.getMonth() && date1.getFullYear() === date2.getFullYear();
1548
+ }
1549
+ function isSameMonth(date1, date2) {
1550
+ return date1.getMonth() === date2.getMonth() && date1.getFullYear() === date2.getFullYear();
1551
+ }
1552
+ function startOfDay(date) {
1553
+ const d = new Date(date);
1554
+ d.setHours(0, 0, 0, 0);
1555
+ return d;
1556
+ }
1557
+ function Calendar({
1558
+ selectedDate,
1559
+ onDateSelect,
1560
+ today = /* @__PURE__ */ new Date(),
1561
+ minDate,
1562
+ maxDate
1563
+ }) {
1564
+ const [currentMonth, setCurrentMonth] = React11.useState(
1565
+ selectedDate || /* @__PURE__ */ new Date()
1566
+ );
1567
+ const todayStart = startOfDay(today);
1568
+ const selectedDateStart = selectedDate ? startOfDay(selectedDate) : null;
1569
+ const firstDayOfMonth = new Date(
1570
+ currentMonth.getFullYear(),
1571
+ currentMonth.getMonth(),
1572
+ 1
1573
+ );
1574
+ const lastDayOfMonth = new Date(
1575
+ currentMonth.getFullYear(),
1576
+ currentMonth.getMonth() + 1,
1577
+ 0
1578
+ );
1579
+ const daysInMonth = lastDayOfMonth.getDate();
1580
+ const startingDayOfWeek = firstDayOfMonth.getDay();
1581
+ const prevMonth = () => {
1582
+ setCurrentMonth(
1583
+ new Date(currentMonth.getFullYear(), currentMonth.getMonth() - 1, 1)
1584
+ );
1585
+ };
1586
+ const nextMonth = () => {
1587
+ setCurrentMonth(
1588
+ new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1, 1)
1589
+ );
1590
+ };
1591
+ const handleDateClick = (day) => {
1592
+ const date = new Date(
1593
+ currentMonth.getFullYear(),
1594
+ currentMonth.getMonth(),
1595
+ day
1596
+ );
1597
+ const dateStart = startOfDay(date);
1598
+ if (minDate && dateStart < startOfDay(minDate)) return;
1599
+ if (maxDate && dateStart > startOfDay(maxDate)) return;
1600
+ onDateSelect(date);
1601
+ };
1602
+ const isDateDisabled = (day) => {
1603
+ const date = new Date(
1604
+ currentMonth.getFullYear(),
1605
+ currentMonth.getMonth(),
1606
+ day
1607
+ );
1608
+ const dateStart = startOfDay(date);
1609
+ if (minDate && dateStart < startOfDay(minDate)) return true;
1610
+ if (maxDate && dateStart > startOfDay(maxDate)) return true;
1611
+ return false;
1612
+ };
1613
+ const days = [];
1614
+ for (let i = 0; i < startingDayOfWeek; i++) {
1615
+ days.push(null);
1616
+ }
1617
+ for (let day = 1; day <= daysInMonth; day++) {
1618
+ days.push(day);
1619
+ }
1620
+ return /* @__PURE__ */ jsxs("div", { className: "w-full", children: [
1621
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-4", children: [
1622
+ /* @__PURE__ */ jsx(
1623
+ "button",
1624
+ {
1625
+ type: "button",
1626
+ onClick: prevMonth,
1627
+ className: "p-2 rounded-full hover:bg-[var(--muted)] transition-colors",
1628
+ "aria-label": "Previous month",
1629
+ children: /* @__PURE__ */ jsx("span", { className: "material-symbols-rounded text-[var(--fg)]", children: "chevron_left" })
1630
+ }
1631
+ ),
1632
+ /* @__PURE__ */ jsxs("h3", { className: "text-sm font-medium text-[var(--fg)]", children: [
1633
+ MONTHS[currentMonth.getMonth()],
1634
+ " ",
1635
+ currentMonth.getFullYear()
1636
+ ] }),
1637
+ /* @__PURE__ */ jsx(
1638
+ "button",
1639
+ {
1640
+ type: "button",
1641
+ onClick: nextMonth,
1642
+ className: "p-2 rounded-full hover:bg-[var(--muted)] transition-colors",
1643
+ "aria-label": "Next month",
1644
+ children: /* @__PURE__ */ jsx("span", { className: "material-symbols-rounded text-[var(--fg)]", children: "chevron_right" })
1645
+ }
1646
+ )
1647
+ ] }),
1648
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-1 mb-2", children: DAYS_OF_WEEK.map((day) => /* @__PURE__ */ jsx(
1649
+ "div",
1650
+ {
1651
+ className: "text-xs text-center text-[var(--muted-fg)] font-medium py-1",
1652
+ children: day
1653
+ },
1654
+ day
1655
+ )) }),
1656
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-1", children: days.map((day, idx) => {
1657
+ if (day === null) {
1658
+ return /* @__PURE__ */ jsx("div", { className: "aspect-square" }, `empty-${idx}`);
1659
+ }
1660
+ const date = new Date(
1661
+ currentMonth.getFullYear(),
1662
+ currentMonth.getMonth(),
1663
+ day
1664
+ );
1665
+ const dateStart = startOfDay(date);
1666
+ const isSelected = selectedDateStart && isSameDay(dateStart, selectedDateStart);
1667
+ const isToday = isSameDay(dateStart, todayStart);
1668
+ const isDisabled = isDateDisabled(day);
1669
+ const isCurrentMonth = isSameMonth(dateStart, currentMonth);
1670
+ return /* @__PURE__ */ jsx(
1671
+ "button",
1672
+ {
1673
+ type: "button",
1674
+ onClick: () => handleDateClick(day),
1675
+ disabled: isDisabled,
1676
+ className: [
1677
+ "aspect-square rounded-lg text-sm transition-colors",
1678
+ isSelected ? "bg-[var(--color-brand)] text-white font-medium" : isToday ? "bg-[var(--muted)] text-[var(--fg)] font-medium border border-[var(--color-brand)]" : "text-[var(--fg)] hover:bg-[var(--muted)]",
1679
+ isDisabled ? "opacity-30 cursor-not-allowed" : "cursor-pointer",
1680
+ !isCurrentMonth ? "opacity-50" : ""
1681
+ ].filter(Boolean).join(" "),
1682
+ children: day
1683
+ },
1684
+ day
1685
+ );
1686
+ }) })
1687
+ ] });
1688
+ }
1689
+ function formatDate(date) {
1690
+ const day = String(date.getDate()).padStart(2, "0");
1691
+ const month = String(date.getMonth() + 1).padStart(2, "0");
1692
+ const year = date.getFullYear();
1693
+ return `${day}/${month}/${year}`;
1694
+ }
1695
+ function parseDate(dateString) {
1696
+ const parts = dateString.split("/");
1697
+ if (parts.length !== 3) return null;
1698
+ const day = parseInt(parts[0], 10);
1699
+ const month = parseInt(parts[1], 10) - 1;
1700
+ const year = parseInt(parts[2], 10);
1701
+ if (isNaN(day) || isNaN(month) || isNaN(year)) return null;
1702
+ const date = new Date(year, month, day);
1703
+ if (date.getDate() !== day || date.getMonth() !== month || date.getFullYear() !== year) {
1704
+ return null;
1705
+ }
1706
+ return date;
1707
+ }
1708
+ function isValidDate(date) {
1709
+ return date instanceof Date && !isNaN(date.getTime());
1710
+ }
1711
+ function startOfDay2(date) {
1712
+ const d = new Date(date);
1713
+ d.setHours(0, 0, 0, 0);
1714
+ return d;
1715
+ }
1716
+ var DateInput = React11.forwardRef(
1717
+ ({
1718
+ label,
1719
+ value,
1720
+ onChange,
1721
+ error = false,
1722
+ disabled = false,
1723
+ minDate,
1724
+ maxDate,
1725
+ placeholder = "00/00/0000",
1726
+ className = "",
1727
+ ...props
1728
+ }, ref) => {
1729
+ const [inputValue, setInputValue] = React11.useState(
1730
+ value && isValidDate(value) ? formatDate(value) : placeholder
1731
+ );
1732
+ const [isFocused, setIsFocused] = React11.useState(false);
1733
+ const [showCalendar, setShowCalendar] = React11.useState(false);
1734
+ const [initialDateSet, setInitialDateSet] = React11.useState(true);
1735
+ const containerRef = React11.useRef(null);
1736
+ React11.useEffect(() => {
1737
+ if (value && isValidDate(value)) {
1738
+ setInputValue(formatDate(value));
1739
+ } else {
1740
+ setInputValue(placeholder);
1741
+ }
1742
+ }, [value, placeholder]);
1743
+ React11.useEffect(() => {
1744
+ if (showCalendar && initialDateSet) {
1745
+ const today = /* @__PURE__ */ new Date();
1746
+ onChange(today);
1747
+ setInputValue(formatDate(today));
1748
+ setInitialDateSet(false);
1749
+ }
1750
+ }, [showCalendar, initialDateSet, onChange]);
1751
+ React11.useEffect(() => {
1752
+ const handleClickOutside = (event) => {
1753
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
1754
+ setShowCalendar(false);
1755
+ setInitialDateSet(false);
1756
+ }
1757
+ };
1758
+ document.addEventListener("mousedown", handleClickOutside);
1759
+ return () => document.removeEventListener("mousedown", handleClickOutside);
1760
+ }, []);
1761
+ const handleInputChange = (e) => {
1762
+ let rawValue = e.target.value;
1763
+ rawValue = rawValue.replace(/\D/g, "").replace(/^(\d{2})/, "$1/").replace(/^(\d{2}\/\d{2})/, "$1/").slice(0, 10);
1764
+ setInputValue(rawValue);
1765
+ if (rawValue.length === 10) {
1766
+ const parsedDate = parseDate(rawValue);
1767
+ if (parsedDate && isValidDate(parsedDate)) {
1768
+ onChange(parsedDate);
1769
+ }
1770
+ }
1771
+ };
1772
+ const handleCalendarSelect = (date) => {
1773
+ const selectedDate = parseDate(inputValue);
1774
+ const sameDay = selectedDate && isValidDate(selectedDate) && selectedDate.getDate() === date.getDate() && selectedDate.getMonth() === date.getMonth() && selectedDate.getFullYear() === date.getFullYear();
1775
+ if (!sameDay) {
1776
+ onChange(date);
1777
+ setInputValue(formatDate(date));
1778
+ }
1779
+ setInitialDateSet(false);
1780
+ setShowCalendar(false);
1781
+ };
1782
+ const handleInputFocus = () => {
1783
+ setIsFocused(true);
1784
+ setShowCalendar(true);
1785
+ };
1786
+ const handleInputBlur = () => {
1787
+ setIsFocused(false);
1788
+ const parsed = parseDate(inputValue);
1789
+ if (!parsed || !isValidDate(parsed)) {
1790
+ const today = /* @__PURE__ */ new Date();
1791
+ onChange(today);
1792
+ setInputValue(formatDate(today));
1793
+ }
1794
+ };
1795
+ const isEmpty = inputValue === placeholder;
1796
+ const textColorClass = isEmpty ? "text-[var(--muted-fg)]" : "";
1797
+ return /* @__PURE__ */ jsxs("div", { className: ["relative w-full", className].join(" "), ref: containerRef, children: [
1798
+ /* @__PURE__ */ jsx(
1799
+ Input,
1800
+ {
1801
+ ref,
1802
+ label,
1803
+ type: "text",
1804
+ value: inputValue,
1805
+ onChange: handleInputChange,
1806
+ onFocus: handleInputFocus,
1807
+ onBlur: handleInputBlur,
1808
+ onClick: () => !disabled && setShowCalendar(true),
1809
+ disabled,
1810
+ error,
1811
+ icon: "calendar_today",
1812
+ className: textColorClass,
1813
+ ...props
1814
+ }
1815
+ ),
1816
+ showCalendar && !disabled && /* @__PURE__ */ jsx("div", { className: "absolute z-20 mt-2 w-full max-w-sm", children: /* @__PURE__ */ jsx(Card, { className: "p-4", showDecorations: false, children: /* @__PURE__ */ jsx(
1817
+ Calendar,
1818
+ {
1819
+ selectedDate: inputValue !== placeholder && parseDate(inputValue) && isValidDate(parseDate(inputValue)) ? parseDate(inputValue) : /* @__PURE__ */ new Date(),
1820
+ onDateSelect: handleCalendarSelect,
1821
+ today: startOfDay2(/* @__PURE__ */ new Date()),
1822
+ minDate,
1823
+ maxDate
1824
+ }
1825
+ ) }) })
1826
+ ] });
1827
+ }
1828
+ );
1829
+ DateInput.displayName = "DateInput";
1519
1830
 
1520
- export { AgentButton_default as AgentButton, AnimatedBgCircle_default as AnimatedBgCircle, AnimatedBgRectangle_default as AnimatedBgRectangle, AppBackground, Autocomplete, Avatar, AvatarGroup, BackgroundBlur, Breadcrumb, Button, Card, Chip, Counter, Icon, IconButton, Input, MessageBubble, Modal, Search, Separator, Skeleton, Textarea, Typo, assets_exports as assets };
1831
+ export { AgentButton_default as AgentButton, AnimatedBgCircle_default as AnimatedBgCircle, AnimatedBgRectangle_default as AnimatedBgRectangle, AppBackground, Autocomplete, Avatar, AvatarGroup, BackgroundBlur, Breadcrumb, Button, Calendar, Card, Chip, Counter, DateInput, Icon, IconButton, Input, MessageBubble, Modal, Search, Separator, Skeleton, Textarea, Typo, assets_exports as assets };