myoperator-mcp 0.2.353 → 0.2.355

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 +127 -142
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7777,36 +7777,32 @@ import {
7777
7777
  useFloating,
7778
7778
  } from "@floating-ui/react-dom";
7779
7779
  import { cva, type VariantProps } from "class-variance-authority";
7780
- import { Search, X } from "lucide-react";
7780
+ import { Check, Search, X } from "lucide-react";
7781
7781
 
7782
7782
  import { cn } from "@/lib/utils";
7783
- import { Button } from "./button";
7784
- import { Checkbox } from "./checkbox";
7785
7783
  import { Input, type InputProps } from "./input";
7786
7784
 
7787
- const searchFilterVariants = cva(
7788
- "relative flex min-w-0 flex-col",
7789
- {
7790
- variants: {
7791
- size: {
7792
- sm: "w-full max-w-80",
7793
- default: "w-full max-w-[360px]",
7794
- lg: "w-full max-w-[420px]",
7795
- },
7796
- },
7797
- defaultVariants: {
7798
- size: "default",
7785
+ const searchFilterVariants = cva("relative flex min-w-0 flex-col", {
7786
+ variants: {
7787
+ size: {
7788
+ sm: "w-full max-w-80",
7789
+ default: "w-full max-w-[360px]",
7790
+ lg: "w-full max-w-[420px]",
7799
7791
  },
7800
- }
7801
- );
7792
+ },
7793
+ defaultVariants: {
7794
+ size: "default",
7795
+ },
7796
+ });
7802
7797
 
7803
- const searchFilterDropdownVariants = cva(
7804
- "flex flex-col overflow-hidden p-0"
7805
- );
7798
+ const searchFilterDropdownVariants = cva("flex flex-col overflow-hidden p-0");
7806
7799
 
7807
7800
  export type SearchFilterSearchMode = "text" | "numeric";
7808
7801
 
7809
- function normalizeSearchText(value: string, searchMode: SearchFilterSearchMode) {
7802
+ function normalizeSearchText(
7803
+ value: string,
7804
+ searchMode: SearchFilterSearchMode
7805
+ ) {
7810
7806
  if (searchMode === "numeric") {
7811
7807
  return value.replace(/\\D/g, "");
7812
7808
  }
@@ -7862,17 +7858,26 @@ function renderHighlightedNumericLabel(label: string, query: string) {
7862
7858
  export interface SearchFilterOption {
7863
7859
  /** Unique option value returned in selection callbacks */
7864
7860
  value: string;
7865
- /** Display label shown beside the checkbox */
7861
+ /** Display label shown in the option list and input after selection */
7866
7862
  label: string;
7867
7863
  /** Disables selection for this row */
7868
7864
  disabled?: boolean;
7869
7865
  }
7870
7866
 
7871
7867
  export interface SearchFilterProps
7872
- extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange">,
7868
+ extends
7869
+ Omit<React.HTMLAttributes<HTMLDivElement>, "onChange">,
7873
7870
  VariantProps<typeof searchFilterVariants> {
7874
7871
  /** Options displayed in the filter list */
7875
7872
  options: SearchFilterOption[];
7873
+ /** Controlled selected option value */
7874
+ value?: string;
7875
+ /** Initial selected option value for uncontrolled usage */
7876
+ defaultValue?: string;
7877
+ /** Called when a single option is selected */
7878
+ onValueChange?: (value: string) => void;
7879
+ /** Called with the full option when a single option is selected */
7880
+ onOptionSelect?: (option: SearchFilterOption) => void;
7876
7881
  /** Controlled search text */
7877
7882
  searchValue?: string;
7878
7883
  /** Initial search text for uncontrolled usage */
@@ -7885,22 +7890,10 @@ export interface SearchFilterProps
7885
7890
  searchMode?: SearchFilterSearchMode;
7886
7891
  /** Message shown when filtering returns no options */
7887
7892
  emptyMessage?: string;
7888
- /** Cancel button label */
7889
- cancelLabel?: string;
7890
- /** Apply button label */
7891
- applyLabel?: string;
7892
- /** Called when Cancel is clicked */
7893
- onCancel?: () => void;
7894
- /** Called with the current selection when Apply is clicked */
7895
- onApply?: (value: string[]) => void;
7896
7893
  /** Disables the whole filter */
7897
7894
  disabled?: boolean;
7898
7895
  /** Disables only the search input */
7899
7896
  searchDisabled?: boolean;
7900
- /** Disables the Cancel button */
7901
- cancelDisabled?: boolean;
7902
- /** Disables the Apply button */
7903
- applyDisabled?: boolean;
7904
7897
  /** Class name for the scrollable options region */
7905
7898
  listClassName?: string;
7906
7899
  /** Additional props for the search input */
@@ -7913,20 +7906,18 @@ const SearchFilter = React.forwardRef<HTMLDivElement, SearchFilterProps>(
7913
7906
  className,
7914
7907
  size,
7915
7908
  options,
7909
+ value,
7910
+ defaultValue,
7911
+ onValueChange,
7912
+ onOptionSelect,
7916
7913
  searchValue,
7917
7914
  defaultSearchValue = "",
7918
7915
  onSearchChange,
7919
7916
  searchPlaceholder = "Search...",
7920
7917
  searchMode = "numeric",
7921
7918
  emptyMessage = "No options found",
7922
- cancelLabel = "Cancel",
7923
- applyLabel = "Apply",
7924
- onCancel,
7925
- onApply,
7926
7919
  disabled = false,
7927
7920
  searchDisabled = false,
7928
- cancelDisabled = false,
7929
- applyDisabled = false,
7930
7921
  listClassName,
7931
7922
  inputProps,
7932
7923
  ...props
@@ -7947,15 +7938,22 @@ const SearchFilter = React.forwardRef<HTMLDivElement, SearchFilterProps>(
7947
7938
  const inputId = React.useId();
7948
7939
  const dropdownId = React.useId();
7949
7940
  const optionIdPrefix = React.useId();
7950
- const [selectedValues, setSelectedValues] = React.useState<string[]>([]);
7941
+ const [internalValue, setInternalValue] = React.useState(
7942
+ defaultValue ?? ""
7943
+ );
7951
7944
  const [internalSearchValue, setInternalSearchValue] =
7952
7945
  React.useState(defaultSearchValue);
7953
7946
  const [isOpen, setIsOpen] = React.useState(false);
7947
+ const selectedValue = value ?? internalValue;
7948
+ const selectedOption = React.useMemo(
7949
+ () => options.find((option) => option.value === selectedValue),
7950
+ [options, selectedValue]
7951
+ );
7954
7952
  const currentSearchValue = searchValue ?? internalSearchValue;
7955
7953
  const displaySearchValue =
7956
- searchMode === "numeric"
7954
+ currentSearchValue && searchMode === "numeric"
7957
7955
  ? normalizeSearchText(currentSearchValue, searchMode)
7958
- : currentSearchValue;
7956
+ : currentSearchValue || selectedOption?.label || "";
7959
7957
  const normalizedSearchQuery = normalizeSearchText(
7960
7958
  currentSearchValue,
7961
7959
  searchMode
@@ -8062,18 +8060,32 @@ const SearchFilter = React.forwardRef<HTMLDivElement, SearchFilterProps>(
8062
8060
  );
8063
8061
  }, [normalizedSearchQuery, options, searchMode]);
8064
8062
 
8065
- const toggleOption = React.useCallback(
8063
+ const selectOption = React.useCallback(
8066
8064
  (option: SearchFilterOption) => {
8067
8065
  if (disabled || option.disabled) return;
8068
8066
 
8069
- const isSelected = selectedValues.includes(option.value);
8070
- setSelectedValues(
8071
- isSelected
8072
- ? selectedValues.filter((item) => item !== option.value)
8073
- : [...selectedValues, option.value]
8074
- );
8067
+ if (value === undefined) {
8068
+ setInternalValue(option.value);
8069
+ }
8070
+
8071
+ if (searchValue === undefined) {
8072
+ setInternalSearchValue(option.label);
8073
+ }
8074
+
8075
+ onValueChange?.(option.value);
8076
+ onOptionSelect?.(option);
8077
+ onSearchChange?.(option.label);
8078
+ setOpen(false);
8075
8079
  },
8076
- [disabled, selectedValues, setSelectedValues]
8080
+ [
8081
+ disabled,
8082
+ onSearchChange,
8083
+ onOptionSelect,
8084
+ onValueChange,
8085
+ searchValue,
8086
+ setOpen,
8087
+ value,
8088
+ ]
8077
8089
  );
8078
8090
 
8079
8091
  const handleSearchChange = (event: React.ChangeEvent<HTMLInputElement>) => {
@@ -8086,6 +8098,9 @@ const SearchFilter = React.forwardRef<HTMLDivElement, SearchFilterProps>(
8086
8098
  if (searchValue === undefined) {
8087
8099
  setInternalSearchValue(nextSearchValue);
8088
8100
  }
8101
+ if (value === undefined && selectedOption?.label !== nextSearchValue) {
8102
+ setInternalValue("");
8103
+ }
8089
8104
  setOpen(true);
8090
8105
  onSearchChange?.(nextSearchValue);
8091
8106
  };
@@ -8094,102 +8109,73 @@ const SearchFilter = React.forwardRef<HTMLDivElement, SearchFilterProps>(
8094
8109
  if (searchValue === undefined) {
8095
8110
  setInternalSearchValue("");
8096
8111
  }
8112
+ if (value === undefined) {
8113
+ setInternalValue("");
8114
+ }
8115
+ onValueChange?.("");
8097
8116
  onSearchChange?.("");
8098
8117
  setOpen(true);
8099
8118
  focusSearchInput();
8100
8119
  };
8101
8120
 
8102
- const handleCancel = () => {
8103
- onCancel?.();
8104
- setOpen(false);
8105
- };
8106
-
8107
- const handleApply = () => {
8108
- onApply?.(selectedValues);
8109
- setOpen(false);
8110
- };
8111
-
8112
8121
  const dropdownPanel = (
8113
- <>
8114
- <div
8115
- className={cn(
8116
- "max-h-60 overflow-auto p-1",
8117
- disabled && "pointer-events-none opacity-60",
8118
- listClassName
8119
- )}
8120
- role="group"
8121
- aria-label="Filter options"
8122
- >
8123
- {filteredOptions.length > 0 ? (
8124
- filteredOptions.map((option, index) => {
8125
- const isSelected = selectedValues.includes(option.value);
8126
- const optionDisabled = disabled || option.disabled;
8122
+ <div
8123
+ className={cn(
8124
+ "max-h-60 overflow-auto p-1",
8125
+ disabled && "pointer-events-none opacity-60",
8126
+ listClassName
8127
+ )}
8128
+ id={dropdownId}
8129
+ role="listbox"
8130
+ aria-label="Filter options"
8131
+ >
8132
+ {filteredOptions.length > 0 ? (
8133
+ filteredOptions.map((option, index) => {
8134
+ const isSelected = selectedValue === option.value;
8135
+ const optionDisabled = disabled || option.disabled;
8127
8136
 
8128
- const optionLabelId = \`\${optionIdPrefix}-\${index}\`;
8137
+ const optionLabelId = \`\${optionIdPrefix}-\${index}\`;
8129
8138
 
8130
- return (
8131
- <div
8132
- key={option.value}
8133
- role="option"
8134
- aria-selected={isSelected}
8135
- aria-disabled={optionDisabled}
8136
- className={cn(
8137
- "relative flex w-full min-w-0 cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-2 text-left text-sm text-semantic-text-primary outline-none",
8138
- !isSelected &&
8139
- "hover:bg-semantic-bg-ui focus:bg-semantic-bg-ui",
8140
- optionDisabled && "cursor-not-allowed opacity-50"
8141
- )}
8142
- onClick={() => toggleOption(option)}
8139
+ return (
8140
+ <button
8141
+ key={option.value}
8142
+ type="button"
8143
+ role="option"
8144
+ aria-selected={isSelected}
8145
+ aria-disabled={optionDisabled}
8146
+ disabled={optionDisabled}
8147
+ className={cn(
8148
+ "relative flex w-full min-w-0 cursor-pointer select-none items-center gap-2 rounded-sm px-4 py-2 pr-9 text-left text-sm text-semantic-text-primary outline-none",
8149
+ !isSelected &&
8150
+ "hover:bg-semantic-bg-ui focus:bg-semantic-bg-ui",
8151
+ isSelected && "bg-semantic-bg-ui",
8152
+ optionDisabled && "cursor-not-allowed opacity-50"
8153
+ )}
8154
+ onClick={() => selectOption(option)}
8155
+ >
8156
+ <span
8157
+ id={optionLabelId}
8158
+ className="min-w-0 flex-1 truncate text-left"
8143
8159
  >
8144
- <Checkbox
8145
- size="sm"
8146
- checked={isSelected}
8147
- disabled={optionDisabled}
8148
- aria-label={option.label}
8149
- className="shrink-0"
8150
- onClick={(event) => event.stopPropagation()}
8151
- onCheckedChange={() => toggleOption(option)}
8152
- />
8153
- <span id={optionLabelId} className="min-w-0 flex-1 truncate text-left">
8154
- {searchMode === "numeric"
8155
- ? renderHighlightedNumericLabel(
8156
- option.label,
8157
- normalizedSearchQuery
8158
- )
8159
- : option.label}
8160
- </span>
8161
- </div>
8162
- );
8163
- })
8164
- ) : (
8165
- <div className="px-4 py-6 text-center text-sm text-semantic-text-muted">
8166
- {emptyMessage}
8167
- </div>
8168
- )}
8169
- </div>
8170
-
8171
- <div className="flex flex-wrap items-center justify-end gap-4 border-t border-solid border-semantic-border-layout p-4">
8172
- <Button
8173
- type="button"
8174
- variant="outline"
8175
- size="lg"
8176
- className="min-w-0 px-4"
8177
- disabled={disabled || cancelDisabled}
8178
- onClick={handleCancel}
8179
- >
8180
- {cancelLabel}
8181
- </Button>
8182
- <Button
8183
- type="button"
8184
- size="lg"
8185
- className="min-w-0 px-4"
8186
- disabled={disabled || applyDisabled}
8187
- onClick={handleApply}
8188
- >
8189
- {applyLabel}
8190
- </Button>
8191
- </div>
8192
- </>
8160
+ {searchMode === "numeric"
8161
+ ? renderHighlightedNumericLabel(
8162
+ option.label,
8163
+ normalizedSearchQuery
8164
+ )
8165
+ : option.label}
8166
+ </span>
8167
+ {isSelected ? (
8168
+ <Check className="pointer-events-none absolute right-3 top-1/2 size-4 -translate-y-1/2 text-semantic-brand" />
8169
+ ) : null}
8170
+ </button>
8171
+ );
8172
+ })
8173
+ ) : (
8174
+ <div className="px-4 py-6 text-center text-sm text-semantic-text-muted">
8175
+ {emptyMessage}
8176
+ </div>
8177
+ )}
8178
+ </div>
8193
8179
  );
8194
8180
 
8195
8181
  return (
@@ -8213,7 +8199,7 @@ const SearchFilter = React.forwardRef<HTMLDivElement, SearchFilterProps>(
8213
8199
  aria-controls={dropdownId}
8214
8200
  aria-expanded={isOpen}
8215
8201
  aria-haspopup="listbox"
8216
- className={cn("h-10 pl-10 pr-9", inputClassName)}
8202
+ className={cn("pl-10 pr-9", inputClassName)}
8217
8203
  {...searchInputProps}
8218
8204
  onClick={(event) => {
8219
8205
  setOpen(true);
@@ -8252,7 +8238,6 @@ const SearchFilter = React.forwardRef<HTMLDivElement, SearchFilterProps>(
8252
8238
  createPortal(
8253
8239
  <div
8254
8240
  ref={setDropdownRef}
8255
- id={dropdownId}
8256
8241
  className={cn(
8257
8242
  "rounded border border-solid border-semantic-border-layout bg-semantic-bg-primary text-semantic-text-primary shadow-md",
8258
8243
  searchFilterDropdownVariants()
@@ -8261,7 +8246,7 @@ const SearchFilter = React.forwardRef<HTMLDivElement, SearchFilterProps>(
8261
8246
  ...floatingStyles,
8262
8247
  zIndex: 10050,
8263
8248
  }}
8264
- role="dialog"
8249
+ role="presentation"
8265
8250
  aria-labelledby={inputId}
8266
8251
  onMouseDown={(event) => event.stopPropagation()}
8267
8252
  >
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myoperator-mcp",
3
- "version": "0.2.353",
3
+ "version": "0.2.355",
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",