myoperator-ui 0.0.170 → 0.0.171

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 (2) hide show
  1. package/dist/index.js +615 -2
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5220,6 +5220,76 @@ const Skeleton = React.forwardRef<HTMLDivElement, SkeletonProps>(
5220
5220
  Skeleton.displayName = "Skeleton";
5221
5221
 
5222
5222
  export { Skeleton, skeletonVariants };
5223
+ `, prefix)
5224
+ }
5225
+ ]
5226
+ },
5227
+ "empty-state": {
5228
+ name: "empty-state",
5229
+ description: "Centered empty state with icon, title, description, and optional action buttons",
5230
+ category: "feedback",
5231
+ dependencies: [
5232
+ "clsx",
5233
+ "tailwind-merge"
5234
+ ],
5235
+ files: [
5236
+ {
5237
+ name: "empty-state.tsx",
5238
+ content: prefixTailwindClasses(`import * as React from "react";
5239
+ import { cn } from "../../lib/utils";
5240
+
5241
+ export interface EmptyStateProps {
5242
+ /** Icon element rendered inside the icon circle */
5243
+ icon?: React.ReactNode;
5244
+ /** Bold heading text */
5245
+ title: React.ReactNode;
5246
+ /** Optional subtitle / description text */
5247
+ description?: React.ReactNode;
5248
+ /** Optional action buttons rendered below the description */
5249
+ actions?: React.ReactNode;
5250
+ /** Additional CSS classes for the root container */
5251
+ className?: string;
5252
+ }
5253
+
5254
+ function EmptyState({
5255
+ icon,
5256
+ title,
5257
+ description,
5258
+ actions,
5259
+ className,
5260
+ }: EmptyStateProps) {
5261
+ return (
5262
+ <div
5263
+ data-slot="empty-state"
5264
+ className={cn(
5265
+ "flex flex-col items-center justify-center gap-5 py-16 px-4",
5266
+ className
5267
+ )}
5268
+ >
5269
+ {icon && (
5270
+ <div className="bg-semantic-primary-surface rounded-[40px] size-[90px] flex items-center justify-center text-semantic-text-secondary">
5271
+ {icon}
5272
+ </div>
5273
+ )}
5274
+ <div className="flex flex-col items-center gap-1.5 text-center">
5275
+ <p className="m-0 text-base font-semibold text-semantic-text-primary">
5276
+ {title}
5277
+ </p>
5278
+ {description && (
5279
+ <p className="m-0 text-sm text-semantic-text-muted max-w-xs">
5280
+ {description}
5281
+ </p>
5282
+ )}
5283
+ </div>
5284
+ {actions && (
5285
+ <div className="flex items-center gap-4">{actions}</div>
5286
+ )}
5287
+ </div>
5288
+ );
5289
+ }
5290
+ EmptyState.displayName = "EmptyState";
5291
+
5292
+ export { EmptyState };
5223
5293
  `, prefix)
5224
5294
  }
5225
5295
  ]
@@ -6007,17 +6077,25 @@ PaginationLink.displayName = "PaginationLink";
6007
6077
  export interface PaginationPreviousProps extends PaginationLinkProps {
6008
6078
  /** Additional CSS classes */
6009
6079
  className?: string;
6080
+ /** Disables the previous button */
6081
+ disabled?: boolean;
6010
6082
  }
6011
6083
 
6012
6084
  function PaginationPrevious({
6013
6085
  className,
6086
+ disabled,
6014
6087
  ...props
6015
6088
  }: PaginationPreviousProps) {
6016
6089
  return (
6017
6090
  <PaginationLink
6018
6091
  aria-label="Go to previous page"
6092
+ aria-disabled={disabled}
6019
6093
  size="default"
6020
- className={cn("gap-1 px-2.5 sm:pl-2.5", className)}
6094
+ className={cn(
6095
+ "gap-1 px-2.5 sm:pl-2.5",
6096
+ disabled && "pointer-events-none opacity-50",
6097
+ className
6098
+ )}
6021
6099
  {...props}
6022
6100
  >
6023
6101
  <ChevronLeftIcon />
@@ -6030,17 +6108,25 @@ PaginationPrevious.displayName = "PaginationPrevious";
6030
6108
  export interface PaginationNextProps extends PaginationLinkProps {
6031
6109
  /** Additional CSS classes */
6032
6110
  className?: string;
6111
+ /** Disables the next button */
6112
+ disabled?: boolean;
6033
6113
  }
6034
6114
 
6035
6115
  function PaginationNext({
6036
6116
  className,
6117
+ disabled,
6037
6118
  ...props
6038
6119
  }: PaginationNextProps) {
6039
6120
  return (
6040
6121
  <PaginationLink
6041
6122
  aria-label="Go to next page"
6123
+ aria-disabled={disabled}
6042
6124
  size="default"
6043
- className={cn("gap-1 px-2.5 sm:pr-2.5", className)}
6125
+ className={cn(
6126
+ "gap-1 px-2.5 sm:pr-2.5",
6127
+ disabled && "pointer-events-none opacity-50",
6128
+ className
6129
+ )}
6044
6130
  {...props}
6045
6131
  >
6046
6132
  <span className="hidden sm:block">Next</span>
@@ -6073,6 +6159,115 @@ function PaginationEllipsis({
6073
6159
  }
6074
6160
  PaginationEllipsis.displayName = "PaginationEllipsis";
6075
6161
 
6162
+ export interface PaginationWidgetProps {
6163
+ /** Current page (1-based) */
6164
+ currentPage: number;
6165
+ /** Total number of pages */
6166
+ totalPages: number;
6167
+ /** Called when the user navigates to a new page */
6168
+ onPageChange: (page: number) => void;
6169
+ /** Number of pages shown on each side of current page (default: 1) */
6170
+ siblingCount?: number;
6171
+ /** Additional CSS classes */
6172
+ className?: string;
6173
+ }
6174
+
6175
+ function usePaginationRange(
6176
+ currentPage: number,
6177
+ totalPages: number,
6178
+ siblingCount: number
6179
+ ): (number | "ellipsis")[] {
6180
+ if (totalPages <= 1) return [1];
6181
+
6182
+ const range = (start: number, end: number): number[] =>
6183
+ Array.from({ length: end - start + 1 }, (_, i) => start + i);
6184
+
6185
+ const leftSibling = Math.max(currentPage - siblingCount, 2);
6186
+ const rightSibling = Math.min(currentPage + siblingCount, totalPages - 1);
6187
+
6188
+ const showLeftEllipsis = leftSibling > 2;
6189
+ const showRightEllipsis = rightSibling < totalPages - 1;
6190
+
6191
+ const pages: (number | "ellipsis")[] = [1];
6192
+
6193
+ if (showLeftEllipsis) {
6194
+ pages.push("ellipsis");
6195
+ } else {
6196
+ // fill in pages between 1 and leftSibling if no ellipsis
6197
+ for (let p = 2; p < leftSibling; p++) pages.push(p);
6198
+ }
6199
+
6200
+ pages.push(...range(leftSibling, rightSibling));
6201
+
6202
+ if (showRightEllipsis) {
6203
+ pages.push("ellipsis");
6204
+ } else {
6205
+ for (let p = rightSibling + 1; p < totalPages; p++) pages.push(p);
6206
+ }
6207
+
6208
+ if (totalPages > 1) pages.push(totalPages);
6209
+
6210
+ return pages;
6211
+ }
6212
+
6213
+ function PaginationWidget({
6214
+ currentPage,
6215
+ totalPages,
6216
+ onPageChange,
6217
+ siblingCount = 1,
6218
+ className,
6219
+ }: PaginationWidgetProps) {
6220
+ const pages = usePaginationRange(currentPage, totalPages, siblingCount);
6221
+
6222
+ return (
6223
+ <Pagination className={className}>
6224
+ <PaginationContent>
6225
+ <PaginationItem>
6226
+ <PaginationPrevious
6227
+ href="#"
6228
+ disabled={currentPage === 1}
6229
+ onClick={(e) => {
6230
+ e.preventDefault();
6231
+ if (currentPage > 1) onPageChange(currentPage - 1);
6232
+ }}
6233
+ />
6234
+ </PaginationItem>
6235
+ {pages.map((page, idx) =>
6236
+ page === "ellipsis" ? (
6237
+ <PaginationItem key={\`ellipsis-\${idx}\`}>
6238
+ <PaginationEllipsis />
6239
+ </PaginationItem>
6240
+ ) : (
6241
+ <PaginationItem key={page}>
6242
+ <PaginationLink
6243
+ href="#"
6244
+ isActive={page === currentPage}
6245
+ onClick={(e) => {
6246
+ e.preventDefault();
6247
+ onPageChange(page);
6248
+ }}
6249
+ >
6250
+ {page}
6251
+ </PaginationLink>
6252
+ </PaginationItem>
6253
+ )
6254
+ )}
6255
+ <PaginationItem>
6256
+ <PaginationNext
6257
+ href="#"
6258
+ disabled={currentPage === totalPages}
6259
+ onClick={(e) => {
6260
+ e.preventDefault();
6261
+ if (currentPage < totalPages) onPageChange(currentPage + 1);
6262
+ }}
6263
+ />
6264
+ </PaginationItem>
6265
+ </PaginationContent>
6266
+ </Pagination>
6267
+ );
6268
+ }
6269
+ PaginationWidget.displayName = "PaginationWidget";
6270
+
6076
6271
  export {
6077
6272
  Pagination,
6078
6273
  PaginationContent,
@@ -6081,6 +6276,7 @@ export {
6081
6276
  PaginationPrevious,
6082
6277
  PaginationNext,
6083
6278
  PaginationEllipsis,
6279
+ PaginationWidget,
6084
6280
  };
6085
6281
  `, prefix)
6086
6282
  }
@@ -8213,6 +8409,423 @@ export interface BankDetailsProps {
8213
8409
  name: "index.ts",
8214
8410
  content: prefixTailwindClasses(`export { BankDetails } from "./bank-details";
8215
8411
  export type { BankDetailsProps, BankDetailItem } from "./types";
8412
+ `, prefix)
8413
+ }
8414
+ ]
8415
+ },
8416
+ "date-range-modal": {
8417
+ name: "date-range-modal",
8418
+ description: "A modal for selecting a date range with start and end date pickers",
8419
+ category: "custom",
8420
+ dependencies: [
8421
+ "clsx",
8422
+ "tailwind-merge",
8423
+ "lucide-react"
8424
+ ],
8425
+ internalDependencies: [
8426
+ "dialog",
8427
+ "button",
8428
+ "input"
8429
+ ],
8430
+ isMultiFile: true,
8431
+ directory: "date-range-modal",
8432
+ mainFile: "index.tsx",
8433
+ files: [
8434
+ {
8435
+ name: "index.tsx",
8436
+ content: prefixTailwindClasses(`import * as React from "react";
8437
+ import {
8438
+ Dialog,
8439
+ DialogContent,
8440
+ DialogHeader,
8441
+ DialogTitle,
8442
+ } from "../dialog";
8443
+ import { Button } from "../button";
8444
+ import { DateInput } from "./date-input";
8445
+
8446
+ export interface DateRangeModalProps {
8447
+ open: boolean;
8448
+ onOpenChange: (open: boolean) => void;
8449
+ /** Modal title. Defaults to "Select custom date" */
8450
+ title?: string;
8451
+ /** Called when the user confirms with both dates selected */
8452
+ onConfirm: (start: Date, end: Date) => void;
8453
+ /** Called when the user cancels */
8454
+ onCancel?: () => void;
8455
+ /** Confirm button label. Defaults to "Select custom date range" */
8456
+ confirmButtonText?: string;
8457
+ /** Cancel button label. Defaults to "Cancel" */
8458
+ cancelButtonText?: string;
8459
+ /** Disables confirm button and shows loading state */
8460
+ loading?: boolean;
8461
+ minDate?: Date;
8462
+ maxDate?: Date;
8463
+ }
8464
+
8465
+ function DateRangeModal({
8466
+ open,
8467
+ onOpenChange,
8468
+ title = "Select custom date",
8469
+ onConfirm,
8470
+ onCancel,
8471
+ confirmButtonText = "Select custom date range",
8472
+ cancelButtonText = "Cancel",
8473
+ loading = false,
8474
+ minDate,
8475
+ maxDate,
8476
+ }: DateRangeModalProps) {
8477
+ const [startDate, setStartDate] = React.useState<Date | undefined>(undefined);
8478
+ const [endDate, setEndDate] = React.useState<Date | undefined>(undefined);
8479
+
8480
+ const canConfirm = !!startDate && !!endDate;
8481
+
8482
+ function handleConfirm() {
8483
+ if (startDate && endDate) {
8484
+ onConfirm(startDate, endDate);
8485
+ }
8486
+ }
8487
+
8488
+ function handleCancel() {
8489
+ onCancel?.();
8490
+ onOpenChange(false);
8491
+ }
8492
+
8493
+ // Reset state when modal closes
8494
+ React.useEffect(() => {
8495
+ if (!open) {
8496
+ setStartDate(undefined);
8497
+ setEndDate(undefined);
8498
+ }
8499
+ }, [open]);
8500
+
8501
+ return (
8502
+ <Dialog open={open} onOpenChange={onOpenChange}>
8503
+ <DialogContent className="sm:max-w-md">
8504
+ <DialogHeader>
8505
+ <DialogTitle>{title}</DialogTitle>
8506
+ </DialogHeader>
8507
+
8508
+ <hr className="border-semantic-border-layout -mx-6" />
8509
+
8510
+ <div className="flex flex-col gap-4 py-2">
8511
+ <DateInput
8512
+ label="Start date"
8513
+ value={startDate}
8514
+ onChange={setStartDate}
8515
+ placeholder="MM/DD/YYYY"
8516
+ minDate={minDate}
8517
+ maxDate={maxDate}
8518
+ />
8519
+ <DateInput
8520
+ label="End date"
8521
+ value={endDate}
8522
+ onChange={setEndDate}
8523
+ placeholder="MM/DD/YYYY"
8524
+ minDate={startDate ?? minDate}
8525
+ maxDate={maxDate}
8526
+ />
8527
+ </div>
8528
+
8529
+ <hr className="border-semantic-border-layout -mx-6" />
8530
+
8531
+ <div className="flex items-center justify-end gap-3 pt-1">
8532
+ <Button variant="outline" onClick={handleCancel} disabled={loading}>
8533
+ {cancelButtonText}
8534
+ </Button>
8535
+ <Button
8536
+ onClick={handleConfirm}
8537
+ disabled={!canConfirm || loading}
8538
+ >
8539
+ {loading ? "Loading..." : confirmButtonText}
8540
+ </Button>
8541
+ </div>
8542
+ </DialogContent>
8543
+ </Dialog>
8544
+ );
8545
+ }
8546
+ DateRangeModal.displayName = "DateRangeModal";
8547
+
8548
+ export { DateRangeModal };
8549
+ `, prefix)
8550
+ },
8551
+ {
8552
+ name: "calendar.tsx",
8553
+ content: prefixTailwindClasses(`import * as React from "react";
8554
+ import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
8555
+ import { cn } from "../../../lib/utils";
8556
+
8557
+ const DAYS_OF_WEEK = ["SU", "MO", "TU", "WE", "TH", "FR", "SA"];
8558
+
8559
+ const MONTHS = [
8560
+ "January", "February", "March", "April", "May", "June",
8561
+ "July", "August", "September", "October", "November", "December",
8562
+ ];
8563
+
8564
+ export interface CalendarProps {
8565
+ value?: Date;
8566
+ onChange: (date: Date) => void;
8567
+ minDate?: Date;
8568
+ maxDate?: Date;
8569
+ }
8570
+
8571
+ function isSameDay(a: Date, b: Date): boolean {
8572
+ return (
8573
+ a.getFullYear() === b.getFullYear() &&
8574
+ a.getMonth() === b.getMonth() &&
8575
+ a.getDate() === b.getDate()
8576
+ );
8577
+ }
8578
+
8579
+ function isBeforeDay(a: Date, b: Date): boolean {
8580
+ const aD = new Date(a.getFullYear(), a.getMonth(), a.getDate());
8581
+ const bD = new Date(b.getFullYear(), b.getMonth(), b.getDate());
8582
+ return aD < bD;
8583
+ }
8584
+
8585
+ function isAfterDay(a: Date, b: Date): boolean {
8586
+ const aD = new Date(a.getFullYear(), a.getMonth(), a.getDate());
8587
+ const bD = new Date(b.getFullYear(), b.getMonth(), b.getDate());
8588
+ return aD > bD;
8589
+ }
8590
+
8591
+ function getDaysInMonth(year: number, month: number): number {
8592
+ return new Date(year, month + 1, 0).getDate();
8593
+ }
8594
+
8595
+ function getFirstDayOfWeek(year: number, month: number): number {
8596
+ return new Date(year, month, 1).getDay();
8597
+ }
8598
+
8599
+ function Calendar({ value, onChange, minDate, maxDate }: CalendarProps) {
8600
+ const today = new Date();
8601
+ const initial = value ?? today;
8602
+
8603
+ const [viewYear, setViewYear] = React.useState(initial.getFullYear());
8604
+ const [viewMonth, setViewMonth] = React.useState(initial.getMonth());
8605
+
8606
+ const daysInMonth = getDaysInMonth(viewYear, viewMonth);
8607
+ const firstDayOfWeek = getFirstDayOfWeek(viewYear, viewMonth);
8608
+
8609
+ // Previous month fill days
8610
+ const prevMonthDays = getDaysInMonth(
8611
+ viewMonth === 0 ? viewYear - 1 : viewYear,
8612
+ viewMonth === 0 ? 11 : viewMonth - 1
8613
+ );
8614
+
8615
+ const handlePrevMonth = () => {
8616
+ if (viewMonth === 0) {
8617
+ setViewMonth(11);
8618
+ setViewYear((y) => y - 1);
8619
+ } else {
8620
+ setViewMonth((m) => m - 1);
8621
+ }
8622
+ };
8623
+
8624
+ const handleNextMonth = () => {
8625
+ if (viewMonth === 11) {
8626
+ setViewMonth(0);
8627
+ setViewYear((y) => y + 1);
8628
+ } else {
8629
+ setViewMonth((m) => m + 1);
8630
+ }
8631
+ };
8632
+
8633
+ const cells: { day: number; currentMonth: boolean; date: Date }[] = [];
8634
+
8635
+ // Fill leading days from previous month
8636
+ for (let i = firstDayOfWeek - 1; i >= 0; i--) {
8637
+ const d = prevMonthDays - i;
8638
+ const prevMonth = viewMonth === 0 ? 11 : viewMonth - 1;
8639
+ const prevYear = viewMonth === 0 ? viewYear - 1 : viewYear;
8640
+ cells.push({ day: d, currentMonth: false, date: new Date(prevYear, prevMonth, d) });
8641
+ }
8642
+
8643
+ // Current month days
8644
+ for (let d = 1; d <= daysInMonth; d++) {
8645
+ cells.push({ day: d, currentMonth: true, date: new Date(viewYear, viewMonth, d) });
8646
+ }
8647
+
8648
+ // Fill trailing days from next month
8649
+ const remainder = cells.length % 7;
8650
+ if (remainder !== 0) {
8651
+ const nextMonth = viewMonth === 11 ? 0 : viewMonth + 1;
8652
+ const nextYear = viewMonth === 11 ? viewYear + 1 : viewYear;
8653
+ for (let d = 1; d <= 7 - remainder; d++) {
8654
+ cells.push({ day: d, currentMonth: false, date: new Date(nextYear, nextMonth, d) });
8655
+ }
8656
+ }
8657
+
8658
+ return (
8659
+ <div className="select-none w-full">
8660
+ {/* Header */}
8661
+ <div className="flex items-center justify-between mb-3">
8662
+ <button
8663
+ type="button"
8664
+ onClick={handlePrevMonth}
8665
+ className="p-1 rounded hover:bg-semantic-bg-hover text-semantic-text-secondary transition-colors"
8666
+ aria-label="Previous month"
8667
+ >
8668
+ <ChevronLeftIcon className="size-4" />
8669
+ </button>
8670
+ <span className="text-sm font-semibold text-semantic-text-primary">
8671
+ {MONTHS[viewMonth]} {viewYear}
8672
+ </span>
8673
+ <button
8674
+ type="button"
8675
+ onClick={handleNextMonth}
8676
+ className="p-1 rounded hover:bg-semantic-bg-hover text-semantic-text-secondary transition-colors"
8677
+ aria-label="Next month"
8678
+ >
8679
+ <ChevronRightIcon className="size-4" />
8680
+ </button>
8681
+ </div>
8682
+
8683
+ {/* Days of week */}
8684
+ <div className="grid grid-cols-7 mb-1">
8685
+ {DAYS_OF_WEEK.map((d) => (
8686
+ <div
8687
+ key={d}
8688
+ className="text-center text-xs font-medium text-semantic-text-muted py-1"
8689
+ >
8690
+ {d}
8691
+ </div>
8692
+ ))}
8693
+ </div>
8694
+
8695
+ {/* Day grid */}
8696
+ <div className="grid grid-cols-7">
8697
+ {cells.map(({ day, currentMonth, date }, idx) => {
8698
+ const isToday = currentMonth && isSameDay(date, today);
8699
+ const isSelected = value ? isSameDay(date, value) : false;
8700
+ const isDisabled =
8701
+ (minDate && isBeforeDay(date, minDate)) ||
8702
+ (maxDate && isAfterDay(date, maxDate));
8703
+
8704
+ return (
8705
+ <button
8706
+ key={idx}
8707
+ type="button"
8708
+ disabled={!!isDisabled}
8709
+ onClick={() => {
8710
+ if (!isDisabled) onChange(date);
8711
+ }}
8712
+ className={cn(
8713
+ "relative flex items-center justify-center size-8 mx-auto rounded-full text-xs transition-colors",
8714
+ isSelected
8715
+ ? "bg-semantic-primary text-semantic-text-inverted font-semibold"
8716
+ : currentMonth
8717
+ ? "text-semantic-text-primary hover:bg-semantic-bg-hover"
8718
+ : "text-semantic-text-muted hover:bg-semantic-bg-hover",
8719
+ isDisabled && "opacity-40 cursor-not-allowed pointer-events-none"
8720
+ )}
8721
+ aria-label={date.toDateString()}
8722
+ aria-pressed={isSelected}
8723
+ aria-current={isToday ? "date" : undefined}
8724
+ >
8725
+ {day}
8726
+ {isToday && !isSelected && (
8727
+ <span className="absolute bottom-0.5 left-1/2 -translate-x-1/2 size-1 rounded-full bg-semantic-primary" />
8728
+ )}
8729
+ </button>
8730
+ );
8731
+ })}
8732
+ </div>
8733
+ </div>
8734
+ );
8735
+ }
8736
+ Calendar.displayName = "Calendar";
8737
+
8738
+ export { Calendar };
8739
+ `, prefix)
8740
+ },
8741
+ {
8742
+ name: "date-input.tsx",
8743
+ content: prefixTailwindClasses(`import * as React from "react";
8744
+ import { CalendarIcon } from "lucide-react";
8745
+ import { cn } from "../../../lib/utils";
8746
+ import { Calendar } from "./calendar";
8747
+
8748
+ export interface DateInputProps {
8749
+ label: string;
8750
+ value?: Date;
8751
+ onChange: (date: Date) => void;
8752
+ placeholder?: string;
8753
+ minDate?: Date;
8754
+ maxDate?: Date;
8755
+ }
8756
+
8757
+ function formatDate(date: Date): string {
8758
+ const mm = String(date.getMonth() + 1).padStart(2, "0");
8759
+ const dd = String(date.getDate()).padStart(2, "0");
8760
+ const yyyy = date.getFullYear();
8761
+ return \`\${mm}/\${dd}/\${yyyy}\`;
8762
+ }
8763
+
8764
+ function DateInput({
8765
+ label,
8766
+ value,
8767
+ onChange,
8768
+ placeholder = "MM/DD/YYYY",
8769
+ minDate,
8770
+ maxDate,
8771
+ }: DateInputProps) {
8772
+ const [open, setOpen] = React.useState(false);
8773
+ const containerRef = React.useRef<HTMLDivElement>(null);
8774
+
8775
+ // Close on outside click
8776
+ React.useEffect(() => {
8777
+ function handleClick(e: MouseEvent) {
8778
+ if (containerRef.current && !containerRef.current.contains(e.target as Node)) {
8779
+ setOpen(false);
8780
+ }
8781
+ }
8782
+ if (open) {
8783
+ document.addEventListener("mousedown", handleClick);
8784
+ }
8785
+ return () => document.removeEventListener("mousedown", handleClick);
8786
+ }, [open]);
8787
+
8788
+ return (
8789
+ <div ref={containerRef} className="relative flex flex-col gap-1.5">
8790
+ <label className="text-sm font-medium text-semantic-text-primary">
8791
+ {label}
8792
+ </label>
8793
+ <button
8794
+ type="button"
8795
+ onClick={() => setOpen((o) => !o)}
8796
+ className={cn(
8797
+ "flex items-center justify-between gap-2 w-full px-3 py-2 rounded-md border text-sm transition-colors outline-none",
8798
+ "border-semantic-border-input bg-semantic-bg-primary text-semantic-text-primary",
8799
+ "hover:border-semantic-border-input-focus/50",
8800
+ open && "border-semantic-border-input-focus/50 shadow-[0_0_0_1px_rgba(43,188,202,0.15)]",
8801
+ !value && "text-semantic-text-muted"
8802
+ )}
8803
+ aria-haspopup="dialog"
8804
+ aria-expanded={open}
8805
+ >
8806
+ <span>{value ? formatDate(value) : placeholder}</span>
8807
+ <CalendarIcon className="size-4 text-semantic-text-muted shrink-0" />
8808
+ </button>
8809
+
8810
+ {open && (
8811
+ <div className="absolute top-full left-0 z-50 mt-1 w-72 rounded-lg border border-semantic-border-layout bg-semantic-bg-primary shadow-lg p-3">
8812
+ <Calendar
8813
+ value={value}
8814
+ onChange={(date) => {
8815
+ onChange(date);
8816
+ setOpen(false);
8817
+ }}
8818
+ minDate={minDate}
8819
+ maxDate={maxDate}
8820
+ />
8821
+ </div>
8822
+ )}
8823
+ </div>
8824
+ );
8825
+ }
8826
+ DateInput.displayName = "DateInput";
8827
+
8828
+ export { DateInput };
8216
8829
  `, prefix)
8217
8830
  }
8218
8831
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myoperator-ui",
3
- "version": "0.0.170",
3
+ "version": "0.0.171",
4
4
  "description": "CLI for adding myOperator UI components to your project",
5
5
  "type": "module",
6
6
  "exports": "./dist/index.js",