myoperator-mcp 0.2.84 → 0.2.86

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 +242 -11
  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";
@@ -3021,6 +3207,8 @@ export interface SelectFieldProps {
3021
3207
  defaultValue?: string;
3022
3208
  /** Callback when value changes */
3023
3209
  onValueChange?: (value: string) => void;
3210
+ /** Callback when an option is selected, provides the full option object */
3211
+ onSelect?: (option: SelectOption) => void;
3024
3212
  /** Options to display */
3025
3213
  options: SelectOption[];
3026
3214
  /** Enable search/filter functionality */
@@ -3069,6 +3257,7 @@ const SelectField = React.forwardRef<HTMLButtonElement, SelectFieldProps>(
3069
3257
  value,
3070
3258
  defaultValue,
3071
3259
  onValueChange,
3260
+ onSelect,
3072
3261
  options,
3073
3262
  searchable,
3074
3263
  searchPlaceholder = "Search...",
@@ -3083,6 +3272,20 @@ const SelectField = React.forwardRef<HTMLButtonElement, SelectFieldProps>(
3083
3272
  // Internal state for search
3084
3273
  const [searchQuery, setSearchQuery] = React.useState("");
3085
3274
 
3275
+ // Handle value change and call both onValueChange and onSelect
3276
+ const handleValueChange = React.useCallback(
3277
+ (newValue: string) => {
3278
+ onValueChange?.(newValue);
3279
+ if (onSelect) {
3280
+ const selectedOption = options.find((o) => o.value === newValue);
3281
+ if (selectedOption) {
3282
+ onSelect(selectedOption);
3283
+ }
3284
+ }
3285
+ },
3286
+ [onValueChange, onSelect, options]
3287
+ );
3288
+
3086
3289
  // Derive state from props
3087
3290
  const derivedState = error ? "error" : "default";
3088
3291
 
@@ -3157,7 +3360,7 @@ const SelectField = React.forwardRef<HTMLButtonElement, SelectFieldProps>(
3157
3360
  <Select
3158
3361
  value={value}
3159
3362
  defaultValue={defaultValue}
3160
- onValueChange={onValueChange}
3363
+ onValueChange={handleValueChange}
3161
3364
  disabled={disabled || loading}
3162
3365
  name={name}
3163
3366
  onOpenChange={handleOpenChange}
@@ -4366,6 +4569,7 @@ const TextField = React.forwardRef<HTMLInputElement, TextFieldProps>(
4366
4569
  onChange,
4367
4570
  disabled,
4368
4571
  id,
4572
+ type,
4369
4573
  ...props
4370
4574
  },
4371
4575
  ref
@@ -4410,10 +4614,13 @@ const TextField = React.forwardRef<HTMLInputElement, TextFieldProps>(
4410
4614
  <input
4411
4615
  ref={ref}
4412
4616
  id={inputId}
4617
+ type={type}
4413
4618
  className={cn(
4414
4619
  hasAddons
4415
4620
  ? "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 })
4621
+ : textFieldInputVariants({ state: derivedState, className }),
4622
+ type === "number" &&
4623
+ "[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
4417
4624
  )}
4418
4625
  disabled={disabled || loading}
4419
4626
  maxLength={maxLength}
@@ -4672,13 +4879,18 @@ export {
4672
4879
  // ============================================================================
4673
4880
 
4674
4881
  const TOAST_LIMIT = 5;
4675
- const TOAST_REMOVE_DELAY = 5000;
4882
+ const TOAST_REMOVE_DELAY = 2000;
4676
4883
 
4677
4884
  type ToasterToast = ToastProps & {
4678
4885
  id: string;
4679
4886
  title?: React.ReactNode;
4680
4887
  description?: React.ReactNode;
4681
4888
  action?: ToastActionElement;
4889
+ /**
4890
+ * Duration in milliseconds before the toast is removed after dismissal.
4891
+ * Defaults to 2000ms (2 seconds).
4892
+ */
4893
+ duration?: number;
4682
4894
  };
4683
4895
 
4684
4896
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -4722,7 +4934,7 @@ interface State {
4722
4934
 
4723
4935
  const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();
4724
4936
 
4725
- const addToRemoveQueue = (toastId: string) => {
4937
+ const addToRemoveQueue = (toastId: string, duration?: number) => {
4726
4938
  if (toastTimeouts.has(toastId)) {
4727
4939
  return;
4728
4940
  }
@@ -4733,7 +4945,7 @@ const addToRemoveQueue = (toastId: string) => {
4733
4945
  type: "REMOVE_TOAST",
4734
4946
  toastId: toastId,
4735
4947
  });
4736
- }, TOAST_REMOVE_DELAY);
4948
+ }, duration ?? TOAST_REMOVE_DELAY);
4737
4949
 
4738
4950
  toastTimeouts.set(toastId, timeout);
4739
4951
  };
@@ -4758,10 +4970,11 @@ export const reducer = (state: State, action: Action): State => {
4758
4970
  const { toastId } = action;
4759
4971
 
4760
4972
  if (toastId) {
4761
- addToRemoveQueue(toastId);
4973
+ const toastItem = state.toasts.find((t) => t.id === toastId);
4974
+ addToRemoveQueue(toastId, toastItem?.duration);
4762
4975
  } else {
4763
- state.toasts.forEach((toast) => {
4764
- addToRemoveQueue(toast.id);
4976
+ state.toasts.forEach((toastItem) => {
4977
+ addToRemoveQueue(toastItem.id, toastItem.duration);
4765
4978
  });
4766
4979
  }
4767
4980
 
@@ -5699,6 +5912,24 @@ var componentMetadata = {
5699
5912
  }
5700
5913
  ]
5701
5914
  },
5915
+ "empty-state": {
5916
+ "name": "EmptyState",
5917
+ "description": "A empty state component.",
5918
+ "dependencies": [
5919
+ "class-variance-authority",
5920
+ "clsx",
5921
+ "tailwind-merge"
5922
+ ],
5923
+ "props": [],
5924
+ "variants": [],
5925
+ "examples": [
5926
+ {
5927
+ "title": "Basic EmptyState",
5928
+ "code": "<EmptyState>Content</EmptyState>",
5929
+ "description": "Simple empty state usage"
5930
+ }
5931
+ ]
5932
+ },
5702
5933
  "form-modal": {
5703
5934
  "name": "FormModal",
5704
5935
  "description": "A form modal component.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myoperator-mcp",
3
- "version": "0.2.84",
3
+ "version": "0.2.86",
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",