myoperator-mcp 0.2.83 → 0.2.85

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 +224 -10
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1683,6 +1683,62 @@ export {
1683
1683
  DropdownMenuSubTrigger,
1684
1684
  DropdownMenuRadioGroup,
1685
1685
  };
1686
+ `,
1687
+ "empty-state": `import * as React from "react";
1688
+ import { cn } from "@/lib/utils";
1689
+
1690
+ export interface EmptyStateProps {
1691
+ /** Icon element rendered inside the icon circle */
1692
+ icon?: React.ReactNode;
1693
+ /** Bold heading text */
1694
+ title: React.ReactNode;
1695
+ /** Optional subtitle / description text */
1696
+ description?: React.ReactNode;
1697
+ /** Optional action buttons rendered below the description */
1698
+ actions?: React.ReactNode;
1699
+ /** Additional CSS classes for the root container */
1700
+ className?: string;
1701
+ }
1702
+
1703
+ function EmptyState({
1704
+ icon,
1705
+ title,
1706
+ description,
1707
+ actions,
1708
+ className,
1709
+ }: EmptyStateProps) {
1710
+ return (
1711
+ <div
1712
+ data-slot="empty-state"
1713
+ className={cn(
1714
+ "flex flex-col items-center justify-center gap-5 py-16 px-4",
1715
+ className
1716
+ )}
1717
+ >
1718
+ {icon && (
1719
+ <div className="bg-semantic-primary-surface rounded-[40px] size-[90px] flex items-center justify-center text-semantic-text-secondary">
1720
+ {icon}
1721
+ </div>
1722
+ )}
1723
+ <div className="flex flex-col items-center gap-1.5 text-center">
1724
+ <p className="m-0 text-base font-semibold text-semantic-text-primary">
1725
+ {title}
1726
+ </p>
1727
+ {description && (
1728
+ <p className="m-0 text-sm text-semantic-text-muted max-w-xs">
1729
+ {description}
1730
+ </p>
1731
+ )}
1732
+ </div>
1733
+ {actions && (
1734
+ <div className="flex items-center gap-4">{actions}</div>
1735
+ )}
1736
+ </div>
1737
+ );
1738
+ }
1739
+ EmptyState.displayName = "EmptyState";
1740
+
1741
+ export { EmptyState };
1686
1742
  `,
1687
1743
  "form-modal": `import * as React from "react";
1688
1744
 
@@ -1867,7 +1923,11 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
1867
1923
  return (
1868
1924
  <input
1869
1925
  type={type}
1870
- className={cn(inputVariants({ state, className }))}
1926
+ className={cn(
1927
+ inputVariants({ state, className }),
1928
+ type === "number" &&
1929
+ "[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
1930
+ )}
1871
1931
  ref={ref}
1872
1932
  {...props}
1873
1933
  />
@@ -2707,17 +2767,25 @@ PaginationLink.displayName = "PaginationLink";
2707
2767
  export interface PaginationPreviousProps extends PaginationLinkProps {
2708
2768
  /** Additional CSS classes */
2709
2769
  className?: string;
2770
+ /** Disables the previous button */
2771
+ disabled?: boolean;
2710
2772
  }
2711
2773
 
2712
2774
  function PaginationPrevious({
2713
2775
  className,
2776
+ disabled,
2714
2777
  ...props
2715
2778
  }: PaginationPreviousProps) {
2716
2779
  return (
2717
2780
  <PaginationLink
2718
2781
  aria-label="Go to previous page"
2782
+ aria-disabled={disabled}
2719
2783
  size="default"
2720
- className={cn("gap-1 px-2.5 sm:pl-2.5", className)}
2784
+ className={cn(
2785
+ "gap-1 px-2.5 sm:pl-2.5",
2786
+ disabled && "pointer-events-none opacity-50",
2787
+ className
2788
+ )}
2721
2789
  {...props}
2722
2790
  >
2723
2791
  <ChevronLeftIcon />
@@ -2730,17 +2798,25 @@ PaginationPrevious.displayName = "PaginationPrevious";
2730
2798
  export interface PaginationNextProps extends PaginationLinkProps {
2731
2799
  /** Additional CSS classes */
2732
2800
  className?: string;
2801
+ /** Disables the next button */
2802
+ disabled?: boolean;
2733
2803
  }
2734
2804
 
2735
2805
  function PaginationNext({
2736
2806
  className,
2807
+ disabled,
2737
2808
  ...props
2738
2809
  }: PaginationNextProps) {
2739
2810
  return (
2740
2811
  <PaginationLink
2741
2812
  aria-label="Go to next page"
2813
+ aria-disabled={disabled}
2742
2814
  size="default"
2743
- className={cn("gap-1 px-2.5 sm:pr-2.5", className)}
2815
+ className={cn(
2816
+ "gap-1 px-2.5 sm:pr-2.5",
2817
+ disabled && "pointer-events-none opacity-50",
2818
+ className
2819
+ )}
2744
2820
  {...props}
2745
2821
  >
2746
2822
  <span className="hidden sm:block">Next</span>
@@ -2773,6 +2849,115 @@ function PaginationEllipsis({
2773
2849
  }
2774
2850
  PaginationEllipsis.displayName = "PaginationEllipsis";
2775
2851
 
2852
+ export interface PaginationWidgetProps {
2853
+ /** Current page (1-based) */
2854
+ currentPage: number;
2855
+ /** Total number of pages */
2856
+ totalPages: number;
2857
+ /** Called when the user navigates to a new page */
2858
+ onPageChange: (page: number) => void;
2859
+ /** Number of pages shown on each side of current page (default: 1) */
2860
+ siblingCount?: number;
2861
+ /** Additional CSS classes */
2862
+ className?: string;
2863
+ }
2864
+
2865
+ function usePaginationRange(
2866
+ currentPage: number,
2867
+ totalPages: number,
2868
+ siblingCount: number
2869
+ ): (number | "ellipsis")[] {
2870
+ if (totalPages <= 1) return [1];
2871
+
2872
+ const range = (start: number, end: number): number[] =>
2873
+ Array.from({ length: end - start + 1 }, (_, i) => start + i);
2874
+
2875
+ const leftSibling = Math.max(currentPage - siblingCount, 2);
2876
+ const rightSibling = Math.min(currentPage + siblingCount, totalPages - 1);
2877
+
2878
+ const showLeftEllipsis = leftSibling > 2;
2879
+ const showRightEllipsis = rightSibling < totalPages - 1;
2880
+
2881
+ const pages: (number | "ellipsis")[] = [1];
2882
+
2883
+ if (showLeftEllipsis) {
2884
+ pages.push("ellipsis");
2885
+ } else {
2886
+ // fill in pages between 1 and leftSibling if no ellipsis
2887
+ for (let p = 2; p < leftSibling; p++) pages.push(p);
2888
+ }
2889
+
2890
+ pages.push(...range(leftSibling, rightSibling));
2891
+
2892
+ if (showRightEllipsis) {
2893
+ pages.push("ellipsis");
2894
+ } else {
2895
+ for (let p = rightSibling + 1; p < totalPages; p++) pages.push(p);
2896
+ }
2897
+
2898
+ if (totalPages > 1) pages.push(totalPages);
2899
+
2900
+ return pages;
2901
+ }
2902
+
2903
+ function PaginationWidget({
2904
+ currentPage,
2905
+ totalPages,
2906
+ onPageChange,
2907
+ siblingCount = 1,
2908
+ className,
2909
+ }: PaginationWidgetProps) {
2910
+ const pages = usePaginationRange(currentPage, totalPages, siblingCount);
2911
+
2912
+ return (
2913
+ <Pagination className={className}>
2914
+ <PaginationContent>
2915
+ <PaginationItem>
2916
+ <PaginationPrevious
2917
+ href="#"
2918
+ disabled={currentPage === 1}
2919
+ onClick={(e) => {
2920
+ e.preventDefault();
2921
+ if (currentPage > 1) onPageChange(currentPage - 1);
2922
+ }}
2923
+ />
2924
+ </PaginationItem>
2925
+ {pages.map((page, idx) =>
2926
+ page === "ellipsis" ? (
2927
+ <PaginationItem key={\`ellipsis-\${idx}\`}>
2928
+ <PaginationEllipsis />
2929
+ </PaginationItem>
2930
+ ) : (
2931
+ <PaginationItem key={page}>
2932
+ <PaginationLink
2933
+ href="#"
2934
+ isActive={page === currentPage}
2935
+ onClick={(e) => {
2936
+ e.preventDefault();
2937
+ onPageChange(page);
2938
+ }}
2939
+ >
2940
+ {page}
2941
+ </PaginationLink>
2942
+ </PaginationItem>
2943
+ )
2944
+ )}
2945
+ <PaginationItem>
2946
+ <PaginationNext
2947
+ href="#"
2948
+ disabled={currentPage === totalPages}
2949
+ onClick={(e) => {
2950
+ e.preventDefault();
2951
+ if (currentPage < totalPages) onPageChange(currentPage + 1);
2952
+ }}
2953
+ />
2954
+ </PaginationItem>
2955
+ </PaginationContent>
2956
+ </Pagination>
2957
+ );
2958
+ }
2959
+ PaginationWidget.displayName = "PaginationWidget";
2960
+
2776
2961
  export {
2777
2962
  Pagination,
2778
2963
  PaginationContent,
@@ -2781,6 +2966,7 @@ export {
2781
2966
  PaginationPrevious,
2782
2967
  PaginationNext,
2783
2968
  PaginationEllipsis,
2969
+ PaginationWidget,
2784
2970
  };
2785
2971
  `,
2786
2972
  "readable-field": `import * as React from "react";
@@ -4366,6 +4552,7 @@ const TextField = React.forwardRef<HTMLInputElement, TextFieldProps>(
4366
4552
  onChange,
4367
4553
  disabled,
4368
4554
  id,
4555
+ type,
4369
4556
  ...props
4370
4557
  },
4371
4558
  ref
@@ -4410,10 +4597,13 @@ const TextField = React.forwardRef<HTMLInputElement, TextFieldProps>(
4410
4597
  <input
4411
4598
  ref={ref}
4412
4599
  id={inputId}
4600
+ type={type}
4413
4601
  className={cn(
4414
4602
  hasAddons
4415
4603
  ? "flex-1 bg-transparent border-0 outline-none focus:ring-0 px-0 h-full text-sm text-semantic-text-primary placeholder:text-semantic-text-placeholder disabled:cursor-not-allowed"
4416
- : textFieldInputVariants({ state: derivedState, className })
4604
+ : textFieldInputVariants({ state: derivedState, className }),
4605
+ type === "number" &&
4606
+ "[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
4417
4607
  )}
4418
4608
  disabled={disabled || loading}
4419
4609
  maxLength={maxLength}
@@ -4672,13 +4862,18 @@ export {
4672
4862
  // ============================================================================
4673
4863
 
4674
4864
  const TOAST_LIMIT = 5;
4675
- const TOAST_REMOVE_DELAY = 5000;
4865
+ const TOAST_REMOVE_DELAY = 2000;
4676
4866
 
4677
4867
  type ToasterToast = ToastProps & {
4678
4868
  id: string;
4679
4869
  title?: React.ReactNode;
4680
4870
  description?: React.ReactNode;
4681
4871
  action?: ToastActionElement;
4872
+ /**
4873
+ * Duration in milliseconds before the toast is removed after dismissal.
4874
+ * Defaults to 2000ms (2 seconds).
4875
+ */
4876
+ duration?: number;
4682
4877
  };
4683
4878
 
4684
4879
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -4722,7 +4917,7 @@ interface State {
4722
4917
 
4723
4918
  const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();
4724
4919
 
4725
- const addToRemoveQueue = (toastId: string) => {
4920
+ const addToRemoveQueue = (toastId: string, duration?: number) => {
4726
4921
  if (toastTimeouts.has(toastId)) {
4727
4922
  return;
4728
4923
  }
@@ -4733,7 +4928,7 @@ const addToRemoveQueue = (toastId: string) => {
4733
4928
  type: "REMOVE_TOAST",
4734
4929
  toastId: toastId,
4735
4930
  });
4736
- }, TOAST_REMOVE_DELAY);
4931
+ }, duration ?? TOAST_REMOVE_DELAY);
4737
4932
 
4738
4933
  toastTimeouts.set(toastId, timeout);
4739
4934
  };
@@ -4758,10 +4953,11 @@ export const reducer = (state: State, action: Action): State => {
4758
4953
  const { toastId } = action;
4759
4954
 
4760
4955
  if (toastId) {
4761
- addToRemoveQueue(toastId);
4956
+ const toastItem = state.toasts.find((t) => t.id === toastId);
4957
+ addToRemoveQueue(toastId, toastItem?.duration);
4762
4958
  } else {
4763
- state.toasts.forEach((toast) => {
4764
- addToRemoveQueue(toast.id);
4959
+ state.toasts.forEach((toastItem) => {
4960
+ addToRemoveQueue(toastItem.id, toastItem.duration);
4765
4961
  });
4766
4962
  }
4767
4963
 
@@ -5699,6 +5895,24 @@ var componentMetadata = {
5699
5895
  }
5700
5896
  ]
5701
5897
  },
5898
+ "empty-state": {
5899
+ "name": "EmptyState",
5900
+ "description": "A empty state component.",
5901
+ "dependencies": [
5902
+ "class-variance-authority",
5903
+ "clsx",
5904
+ "tailwind-merge"
5905
+ ],
5906
+ "props": [],
5907
+ "variants": [],
5908
+ "examples": [
5909
+ {
5910
+ "title": "Basic EmptyState",
5911
+ "code": "<EmptyState>Content</EmptyState>",
5912
+ "description": "Simple empty state usage"
5913
+ }
5914
+ ]
5915
+ },
5702
5916
  "form-modal": {
5703
5917
  "name": "FormModal",
5704
5918
  "description": "A form modal component.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myoperator-mcp",
3
- "version": "0.2.83",
3
+ "version": "0.2.85",
4
4
  "description": "MCP server for myOperator UI components - enables AI assistants to access component metadata, examples, and design tokens",
5
5
  "type": "module",
6
6
  "bin": "./dist/index.js",