myoperator-mcp 0.2.60 → 0.2.62

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 +211 -0
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2605,6 +2605,198 @@ const PageHeader = React.forwardRef<HTMLDivElement, PageHeaderProps>(
2605
2605
  PageHeader.displayName = "PageHeader";
2606
2606
 
2607
2607
  export { PageHeader, pageHeaderVariants };
2608
+ `,
2609
+ "readable-field": `import * as React from "react";
2610
+ import { Copy, Check, Eye, EyeOff } from "lucide-react";
2611
+ import { cn } from "@/lib/utils";
2612
+
2613
+ export interface ReadableFieldProps
2614
+ extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
2615
+ /** Label text displayed above the field */
2616
+ label: string;
2617
+ /** Value to display and copy */
2618
+ value: string;
2619
+ /** Helper text displayed below the field */
2620
+ helperText?: string;
2621
+ /** When true, masks the value with dots and shows eye toggle */
2622
+ secret?: boolean;
2623
+ /** Header action (e.g., "Regenerate" link) */
2624
+ headerAction?: {
2625
+ label: string;
2626
+ onClick: () => void;
2627
+ };
2628
+ /** Callback when value is copied */
2629
+ onValueCopy?: (value: string) => void;
2630
+ /** Additional class for the input container */
2631
+ inputClassName?: string;
2632
+ }
2633
+
2634
+ /**
2635
+ * ReadableField displays a read-only value with copy-to-clipboard functionality.
2636
+ * Supports secret mode for sensitive data like API keys and passwords.
2637
+ *
2638
+ * @example
2639
+ * \`\`\`tsx
2640
+ * // Simple readable field
2641
+ * <ReadableField
2642
+ * label="Base URL"
2643
+ * value="https://api.myoperator.co/v3/voice/gateway"
2644
+ * />
2645
+ *
2646
+ * // Secret field with regenerate action
2647
+ * <ReadableField
2648
+ * label="Authentication"
2649
+ * value="sk_live_abc123xyz"
2650
+ * secret
2651
+ * helperText="Used for client-side integrations."
2652
+ * headerAction={{
2653
+ * label: "Regenerate",
2654
+ * onClick: () => console.log("Regenerate clicked"),
2655
+ * }}
2656
+ * />
2657
+ * \`\`\`
2658
+ */
2659
+ export const ReadableField = React.forwardRef<HTMLDivElement, ReadableFieldProps>(
2660
+ (
2661
+ {
2662
+ label,
2663
+ value,
2664
+ helperText,
2665
+ secret = false,
2666
+ headerAction,
2667
+ onValueCopy,
2668
+ className,
2669
+ inputClassName,
2670
+ ...props
2671
+ },
2672
+ ref
2673
+ ) => {
2674
+ const [copied, setCopied] = React.useState(false);
2675
+ const [isVisible, setIsVisible] = React.useState(!secret);
2676
+ const timeoutRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);
2677
+
2678
+ // Sync visibility state when secret prop changes
2679
+ React.useEffect(() => {
2680
+ setIsVisible(!secret);
2681
+ }, [secret]);
2682
+
2683
+ // Cleanup timeout on unmount to prevent memory leaks
2684
+ React.useEffect(() => {
2685
+ return () => {
2686
+ if (timeoutRef.current) {
2687
+ clearTimeout(timeoutRef.current);
2688
+ }
2689
+ };
2690
+ }, []);
2691
+
2692
+ const handleCopy = async () => {
2693
+ try {
2694
+ await navigator.clipboard.writeText(value);
2695
+ setCopied(true);
2696
+ onValueCopy?.(value);
2697
+
2698
+ // Clear existing timeout before setting new one
2699
+ if (timeoutRef.current) {
2700
+ clearTimeout(timeoutRef.current);
2701
+ }
2702
+ timeoutRef.current = setTimeout(() => setCopied(false), 2000);
2703
+ } catch {
2704
+ // Clipboard API may fail in insecure contexts
2705
+ }
2706
+ };
2707
+
2708
+ const toggleVisibility = () => {
2709
+ setIsVisible((prev) => !prev);
2710
+ };
2711
+
2712
+ // Display masked or actual value
2713
+ const displayValue = secret && !isVisible ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : value;
2714
+
2715
+ return (
2716
+ <div
2717
+ ref={ref}
2718
+ className={cn("flex flex-col gap-1", className)}
2719
+ {...props}
2720
+ >
2721
+ {/* Header Row: Label + Optional Action */}
2722
+ <div className="flex items-start justify-between">
2723
+ <span className="text-sm text-semantic-text-muted tracking-[0.035px]">
2724
+ {label}
2725
+ </span>
2726
+ {headerAction && (
2727
+ <button
2728
+ type="button"
2729
+ onClick={headerAction.onClick}
2730
+ className="text-sm font-semibold text-semantic-text-muted tracking-[0.014px] hover:text-semantic-text-primary focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-semantic-text-primary rounded transition-colors"
2731
+ >
2732
+ {headerAction.label}
2733
+ </button>
2734
+ )}
2735
+ </div>
2736
+
2737
+ {/* Input Container */}
2738
+ <div
2739
+ className={cn(
2740
+ "flex h-11 items-center justify-between rounded border border-semantic-border-layout bg-semantic-bg-ui pl-4 pr-2.5 py-2.5",
2741
+ inputClassName
2742
+ )}
2743
+ >
2744
+ {/* Value Display */}
2745
+ <span className="text-base text-[var(--color-primary-950)] tracking-[0.08px] truncate">
2746
+ {displayValue}
2747
+ </span>
2748
+
2749
+ {/* Action Icons */}
2750
+ <div className="flex items-center gap-4 shrink-0">
2751
+ {/* Eye Toggle (only for secret mode) */}
2752
+ {secret && (
2753
+ <button
2754
+ type="button"
2755
+ onClick={toggleVisibility}
2756
+ className="text-semantic-text-muted hover:text-semantic-text-primary focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-semantic-text-primary rounded transition-colors"
2757
+ aria-label={isVisible ? "Hide value" : "Show value"}
2758
+ >
2759
+ {isVisible ? (
2760
+ <EyeOff className="size-[18px]" />
2761
+ ) : (
2762
+ <Eye className="size-[18px]" />
2763
+ )}
2764
+ </button>
2765
+ )}
2766
+
2767
+ {/* Copy Button */}
2768
+ <button
2769
+ type="button"
2770
+ onClick={handleCopy}
2771
+ className={cn(
2772
+ "rounded transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-semantic-text-primary",
2773
+ copied
2774
+ ? "text-semantic-success-primary"
2775
+ : "text-semantic-text-muted hover:text-semantic-text-primary"
2776
+ )}
2777
+ aria-label={copied ? "Copied" : "Copy to clipboard"}
2778
+ >
2779
+ {copied ? (
2780
+ <Check className="size-[18px]" />
2781
+ ) : (
2782
+ <Copy className="size-[18px]" />
2783
+ )}
2784
+ </button>
2785
+ </div>
2786
+ </div>
2787
+
2788
+ {/* Helper Text */}
2789
+ {helperText && (
2790
+ <p className="m-0 text-sm text-semantic-text-muted tracking-[0.035px]">
2791
+ {helperText}
2792
+ </p>
2793
+ )}
2794
+ </div>
2795
+ );
2796
+ }
2797
+ );
2798
+
2799
+ ReadableField.displayName = "ReadableField";
2608
2800
  `,
2609
2801
  "select-field": `import * as React from "react";
2610
2802
  import { Loader2 } from "lucide-react";
@@ -5275,6 +5467,25 @@ var componentMetadata = {
5275
5467
  }
5276
5468
  ]
5277
5469
  },
5470
+ "readable-field": {
5471
+ "name": "ReadableField",
5472
+ "description": "A readable field component.",
5473
+ "dependencies": [
5474
+ "class-variance-authority",
5475
+ "clsx",
5476
+ "tailwind-merge",
5477
+ "lucide-react"
5478
+ ],
5479
+ "props": [],
5480
+ "variants": [],
5481
+ "examples": [
5482
+ {
5483
+ "title": "Basic ReadableField",
5484
+ "code": "<ReadableField>Content</ReadableField>",
5485
+ "description": "Simple readable field usage"
5486
+ }
5487
+ ]
5488
+ },
5278
5489
  "select-field": {
5279
5490
  "name": "SelectField",
5280
5491
  "description": "A form-ready select component with label, helper text, error handling, and grouped options support.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myoperator-mcp",
3
- "version": "0.2.60",
3
+ "version": "0.2.62",
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",