myoperator-mcp 0.2.259 → 0.2.261

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 +161 -213
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -815,13 +815,7 @@ import { cva, type VariantProps } from "class-variance-authority";
815
815
  import { cn } from "@/lib/utils";
816
816
 
817
817
  const DOT_KEYS = [0, 1, 2] as const;
818
-
819
- /** Delays (seconds) for \`type="staggered"\` \u2014 matches the common 0.1s / 0.3s / 0.6s pattern. */
820
- const STAGGERED_BOUNCE_DELAYS_SEC = [0.1, 0.3, 0.6] as const;
821
-
822
- export type BouncingLoaderType = "default" | "staggered";
823
-
824
- export type BouncingLoaderFrame = "none" | "pill";
818
+ const DOT_DELAYS_SEC = [0, 0.2, 0.4] as const;
825
819
 
826
820
  function toCssLength(value: number | string, unit: string): string {
827
821
  if (typeof value === "string") {
@@ -831,34 +825,12 @@ function toCssLength(value: number | string, unit: string): string {
831
825
  }
832
826
 
833
827
  const bouncingLoaderVariants = cva(
834
- "bouncing-loader min-w-0 items-center justify-center leading-[0] align-middle gap-[var(--bouncing-loader-spacing,0.375rem)]",
835
- {
836
- variants: {
837
- fullWidth: {
838
- true: "bouncing-loader--full-width flex w-full",
839
- false: "inline-flex shrink-0",
840
- },
841
- },
842
- defaultVariants: {
843
- fullWidth: false,
844
- },
845
- }
828
+ "bouncing-loader inline-flex shrink-0 min-w-0 items-center justify-center leading-[0] align-middle gap-[var(--bouncing-loader-spacing,0.375rem)]"
846
829
  );
847
830
 
848
831
  export interface BouncingLoaderProps
849
- extends Omit<React.HTMLAttributes<HTMLSpanElement>, "type">,
832
+ extends React.HTMLAttributes<HTMLSpanElement>,
850
833
  VariantProps<typeof bouncingLoaderVariants> {
851
- /**
852
- * \`default\` \u2014 \`effect\` controls the animation.
853
- * \`staggered\` \u2014 Tailwind \`animate-bounce\` with **0.5s** duration and per-dot delays
854
- * **0.1s / 0.3s / 0.6s** (overrides \`effect\` for the animation). Sensible defaults: 20px dots,
855
- * 12px gap, \`var(--color-neutral-800)\` (override with \`size\` / \`spacing\` / \`color\`).
856
- */
857
- type?: BouncingLoaderType;
858
- /**
859
- * \`pill\` \u2014 white rounded container with padding (like \`bg-white p-5 rounded-full\` around the row).
860
- */
861
- frame?: BouncingLoaderFrame;
862
834
  /**
863
835
  * Dot diameter. Number is treated as pixels; string is used as a CSS length
864
836
  * (e.g. \`"0.5rem"\`, \`"12px"\`).
@@ -866,144 +838,45 @@ export interface BouncingLoaderProps
866
838
  size?: number | string;
867
839
  /**
868
840
  * Dot fill. Any valid CSS color (e.g. semantic token: \`var(--semantic-text-placeholder)\`).
869
- * When omitted, the placeholder token is used via the default background chain.
870
- * Use with \`colorDark\` to mirror \`bg-\u2026\` / \`dark:bg-\u2026\` in plain HTML.
871
841
  */
872
842
  color?: string;
873
- /**
874
- * Optional dot fill when \`.dark\` is on an ancestor. If omitted, one fill (from \`color\` or
875
- * the default placeholder) is used in both themes.
876
- */
877
- colorDark?: string;
878
843
  /**
879
844
  * Space between dots. Number is pixel gap; string is a CSS length (e.g. \`"0.5rem"\`).
880
845
  */
881
846
  spacing?: number | string;
882
- /**
883
- * Extra delay per dot (seconds) as \`i * delay\`. \`wave\` defaults to \`duration/3\`;
884
- * \`dots-bounce\` / \`tailwind-bounce\` default to \`0.2\` (0s / 0.2s / 0.4s); \`bounce\` defaults
885
- * to \`0.12s\`.
886
- */
887
- staggerDelay?: number;
888
- /**
889
- * One full animation loop (seconds) per dot, via \`--bouncing-loader-duration\`.
890
- */
891
- duration?: number;
892
- /**
893
- * Vertical travel at the peak. Number = pixels; string = any CSS length. Sets
894
- * \`--bouncing-loader-bounce\`.
895
- */
896
- bounce?: number | string;
897
- /**
898
- * \`wave\` (default) \u2014 one quick lift per cycle, staggered: classic typing-dot wave.
899
- * \`bounce\` \u2014 each dot runs a continuous up/down loop (sine-like bounce, not a row wave).
900
- * \`dots-bounce\` \u2014 Tailwind\u2019s \`animate-bounce\` with staggered delays
901
- * (default 0.2s, like 0s / 0.2s / 0.4s). Alias: \`tailwind-bounce\`.
902
- */
903
- effect?: "wave" | "bounce" | "dots-bounce" | "tailwind-bounce";
904
847
  }
905
848
 
906
849
  const BouncingLoader = React.forwardRef<HTMLSpanElement, BouncingLoaderProps>(
907
- (
908
- {
909
- className,
910
- type: typeProp = "default",
911
- frame = "none",
912
- size,
913
- color,
914
- colorDark,
915
- spacing,
916
- staggerDelay: staggerProp,
917
- duration: userDuration,
918
- bounce = 4,
919
- effect = "wave",
920
- fullWidth,
921
- style,
922
- ...props
923
- },
924
- ref
925
- ) => {
926
- const isStaggeredType = typeProp === "staggered";
927
- const isDotsBounce =
928
- isStaggeredType || effect === "dots-bounce" || effect === "tailwind-bounce";
929
-
930
- const duration = userDuration ?? (isStaggeredType ? 0.5 : isDotsBounce ? 1 : 0.6);
931
-
932
- const staggerDelay =
933
- staggerProp ??
934
- (effect === "wave" && !isStaggeredType
935
- ? duration / 3
936
- : isDotsBounce
937
- ? 0.2
938
- : 0.12);
939
-
940
- const waveClass = !isDotsBounce && effect === "wave" && "animate-bouncing-typing-wave";
941
- const bounceClass = !isDotsBounce && effect === "bounce" && "animate-bouncing-bounce";
942
- const dotsBounceClass = isDotsBounce && "animate-bounce";
943
-
944
- const effectiveSize = size ?? (isStaggeredType ? 20 : undefined);
945
- const effectiveSpacing = spacing ?? (isStaggeredType ? 12 : undefined);
946
- const effectiveColor = color ?? (isStaggeredType ? "var(--color-neutral-800)" : undefined);
947
-
948
- const dotBgClass =
949
- colorDark !== undefined
950
- ? "bg-[var(--bouncing-loader-color,var(--semantic-text-placeholder,currentColor))] dark:bg-[var(--bouncing-loader-color-dark)]"
951
- : "bg-[var(--bouncing-loader-color,var(--semantic-text-placeholder,currentColor))]";
952
-
953
- const animationDelayForDot = (i: number): string => {
954
- if (isStaggeredType) {
955
- if (staggerProp !== undefined) {
956
- return \`\${i * staggerProp}s\`;
957
- }
958
- return \`\${STAGGERED_BOUNCE_DELAYS_SEC[i]}s\`;
959
- }
960
- return \`\${i * staggerDelay}s\`;
961
- };
962
-
850
+ ({ className, size, color, spacing, style, ...props }, ref) => {
963
851
  const mergedStyle: React.CSSProperties = {
964
852
  ...style,
965
- ...(effectiveSize !== undefined && {
966
- ["--bouncing-loader-size" as string]: toCssLength(effectiveSize, "px"),
967
- }),
968
- ...(effectiveColor !== undefined && {
969
- ["--bouncing-loader-color" as string]: effectiveColor,
853
+ ...(size !== undefined && {
854
+ ["--bouncing-loader-size" as string]: toCssLength(size, "px"),
970
855
  }),
971
- ...(colorDark !== undefined && {
972
- ["--bouncing-loader-color-dark" as string]: colorDark,
856
+ ...(color !== undefined && {
857
+ ["--bouncing-loader-color" as string]: color,
973
858
  }),
974
- ...(effectiveSpacing !== undefined && {
975
- ["--bouncing-loader-spacing" as string]: toCssLength(effectiveSpacing, "px"),
859
+ ...(spacing !== undefined && {
860
+ ["--bouncing-loader-spacing" as string]: toCssLength(spacing, "px"),
976
861
  }),
977
- ["--bouncing-loader-duration" as string]: \`\${duration}s\`,
978
- ["--bouncing-loader-bounce" as string]: toCssLength(bounce, "px"),
979
862
  };
980
863
 
981
864
  return (
982
865
  <span
983
866
  ref={ref}
984
- className={cn(
985
- bouncingLoaderVariants({ fullWidth }),
986
- frame === "pill" && "rounded-full bg-white p-5",
987
- className
988
- )}
867
+ role="status"
868
+ aria-live="polite"
869
+ aria-label="Loading"
870
+ className={cn(bouncingLoaderVariants(), className)}
989
871
  style={mergedStyle}
990
872
  {...props}
991
873
  >
992
874
  {DOT_KEYS.map((i) => (
993
875
  <span
994
876
  key={i}
995
- className={cn(
996
- "bouncing-loader__dot box-border block h-[var(--bouncing-loader-size,8px)] w-[var(--bouncing-loader-size,8px)] shrink-0 rounded-full",
997
- dotBgClass,
998
- waveClass,
999
- bounceClass,
1000
- dotsBounceClass
1001
- )}
877
+ className="bouncing-loader__dot box-border block h-[var(--bouncing-loader-size,8px)] w-[var(--bouncing-loader-size,8px)] shrink-0 rounded-full bg-[var(--bouncing-loader-color,var(--semantic-text-placeholder,currentColor))] animate-bouncing-typing-wave"
1002
878
  style={{
1003
- animationDelay: animationDelayForDot(i),
1004
- ...(isDotsBounce && {
1005
- animationDuration: \`\${duration}s\`,
1006
- }),
879
+ ["--bouncing-loader-delay" as string]: \`\${DOT_DELAYS_SEC[i]}s\`,
1007
880
  }}
1008
881
  aria-hidden
1009
882
  />
@@ -1619,6 +1492,11 @@ export interface CreatableMultiSelectProps
1619
1492
  * Set to false to match Figma (counter lives only in the field flow / not under the control).
1620
1493
  */
1621
1494
  showPerItemCharacterCounter?: boolean
1495
+ /**
1496
+ * Closed trigger: show removable chips (default) or a single comma-separated summary line (Figma Tone).
1497
+ * While open, the trigger always shows the summary line; selected chips with remove controls appear in the panel.
1498
+ */
1499
+ triggerDisplay?: "chips" | "summary"
1622
1500
  /**
1623
1501
  * When set, the text input is transformed (e.g. strip invalid characters).
1624
1502
  * If the raw value differs from the sanitized value, \`onInvalidCharacters\` is called.
@@ -1664,6 +1542,7 @@ const CreatableMultiSelect = React.forwardRef(
1664
1542
  maxItems,
1665
1543
  maxLengthPerItem,
1666
1544
  showPerItemCharacterCounter = true,
1545
+ triggerDisplay = "chips",
1667
1546
  sanitizeInput,
1668
1547
  onInvalidCharacters,
1669
1548
  onValidInput,
@@ -1764,13 +1643,10 @@ const CreatableMultiSelect = React.forwardRef(
1764
1643
  !value.includes(draftForCreate) &&
1765
1644
  (maxItems == null || value.length < maxItems)
1766
1645
 
1767
- const hasHintCopy = Boolean(createHintText) || maxItems != null
1646
+ const panelInputPlaceholder = createHintText ?? placeholder
1768
1647
 
1769
- const showHintsSection = hasHintCopy || canShowEnterAffordance
1770
-
1771
- const inputPlaceholder = isOpen
1772
- ? selectedSummary || placeholder
1773
- : ""
1648
+ const summaryTriggerLabel =
1649
+ value.length === 0 ? placeholder : selectedSummary
1774
1650
 
1775
1651
  return (
1776
1652
  <div
@@ -1779,48 +1655,33 @@ const CreatableMultiSelect = React.forwardRef(
1779
1655
  {...props}
1780
1656
  >
1781
1657
  <div className="relative w-full">
1782
- {isOpen ? (
1658
+ {isOpen && (
1783
1659
  <div
1784
1660
  className={cn(
1785
1661
  creatableSelectTriggerVariants({ state: derivedState }),
1786
- "cursor-text"
1662
+ "flex h-auto min-h-[42px] cursor-text items-start gap-2 py-2 text-left"
1787
1663
  )}
1788
- onClick={() => inputRef.current?.focus()}
1664
+ onClick={() => !disabled && inputRef.current?.focus()}
1665
+ aria-hidden="true"
1789
1666
  >
1790
- <input
1791
- ref={inputRef}
1792
- type="text"
1793
- value={inputValue}
1794
- onChange={(e) => {
1795
- const raw = e.target.value
1796
- const sanitized = sanitizeInput ? sanitizeInput(raw) : raw
1797
- if (sanitizeInput) {
1798
- if (raw !== sanitized) onInvalidCharacters?.()
1799
- else onValidInput?.()
1800
- }
1801
- setInputValue(
1802
- maxLengthPerItem != null
1803
- ? sanitized.slice(0, maxLengthPerItem)
1804
- : sanitized
1805
- )
1806
- }}
1807
- maxLength={maxLengthPerItem}
1808
- onKeyDown={handleKeyDown}
1809
- disabled={disabled}
1810
- placeholder={inputPlaceholder}
1811
- className="flex-1 min-w-0 bg-transparent outline-none text-base text-semantic-text-primary placeholder:text-semantic-text-muted"
1812
- role="combobox"
1813
- aria-expanded={isOpen}
1814
- aria-controls={listboxId}
1815
- aria-haspopup="listbox"
1816
- aria-autocomplete="list"
1817
- />
1667
+ <span
1668
+ className={cn(
1669
+ "line-clamp-2 min-w-0 flex-1 text-base",
1670
+ value.length === 0
1671
+ ? "text-semantic-text-muted"
1672
+ : "text-semantic-text-primary"
1673
+ )}
1674
+ >
1675
+ {summaryTriggerLabel}
1676
+ </span>
1818
1677
  <ChevronRight
1819
- className="size-5 text-semantic-text-muted shrink-0 opacity-70"
1678
+ className="mt-1 size-5 shrink-0 self-start text-semantic-text-muted opacity-70"
1820
1679
  aria-hidden
1821
1680
  />
1822
1681
  </div>
1823
- ) : (
1682
+ )}
1683
+
1684
+ {!isOpen && (
1824
1685
  <div
1825
1686
  role="combobox"
1826
1687
  tabIndex={disabled ? -1 : 0}
@@ -1844,12 +1705,23 @@ const CreatableMultiSelect = React.forwardRef(
1844
1705
  }}
1845
1706
  className={cn(
1846
1707
  creatableSelectTriggerVariants({ state: derivedState }),
1847
- "flex min-h-[42px] cursor-pointer items-center gap-2 py-1 text-left outline-none focus-visible:ring-2 focus-visible:ring-semantic-border-focus focus-visible:ring-offset-2 focus-visible:ring-offset-semantic-bg-primary",
1708
+ "flex h-auto min-h-[42px] cursor-pointer items-start gap-2 py-2 text-left outline-none focus-visible:ring-2 focus-visible:ring-semantic-border-focus focus-visible:ring-offset-2 focus-visible:ring-offset-semantic-bg-primary",
1848
1709
  disabled && "pointer-events-none cursor-not-allowed"
1849
1710
  )}
1850
1711
  >
1851
- <div className="flex min-h-0 min-w-0 flex-1 flex-wrap items-center gap-1.5">
1852
- {value.length === 0 ? (
1712
+ <div className="flex min-h-0 min-w-0 flex-1 flex-wrap content-start items-center gap-1.5">
1713
+ {triggerDisplay === "summary" ? (
1714
+ <span
1715
+ className={cn(
1716
+ "line-clamp-2 flex-1 text-base",
1717
+ value.length === 0
1718
+ ? "text-semantic-text-muted"
1719
+ : "text-semantic-text-primary"
1720
+ )}
1721
+ >
1722
+ {summaryTriggerLabel}
1723
+ </span>
1724
+ ) : value.length === 0 ? (
1853
1725
  <span
1854
1726
  className={cn(
1855
1727
  "line-clamp-2 flex-1 text-base",
@@ -1893,52 +1765,128 @@ const CreatableMultiSelect = React.forwardRef(
1893
1765
  )}
1894
1766
  </div>
1895
1767
  <ChevronRight
1896
- className="size-5 shrink-0 text-semantic-text-muted opacity-70"
1768
+ className="mt-1 size-5 shrink-0 self-start text-semantic-text-muted opacity-70"
1897
1769
  aria-hidden
1898
1770
  />
1899
1771
  </div>
1900
1772
  )}
1901
1773
 
1902
- {/* Dropdown panel */}
1774
+ {/* Dropdown panel: input + limits + presets (Figma: summary row stays above; type-to-create lives here) */}
1903
1775
  {isOpen && (
1904
1776
  <div
1905
- id={listboxId}
1906
- role="listbox"
1907
- className="absolute left-0 top-full z-[9999] mt-1 flex w-full flex-col gap-2.5 overflow-hidden rounded border border-solid border-semantic-border-layout bg-semantic-bg-primary px-4 pb-4 pt-0 shadow-sm animate-in fade-in-0 zoom-in-95 slide-in-from-top-2 duration-200"
1777
+ className="absolute left-0 top-full z-[9999] mt-1 flex w-full flex-col overflow-hidden rounded border border-solid border-semantic-border-layout bg-semantic-bg-primary shadow-sm animate-in fade-in-0 zoom-in-95 slide-in-from-top-2 duration-200"
1908
1778
  >
1909
- {showHintsSection && (
1910
- <div className="-mx-4 flex shrink-0 flex-col border-b border-solid border-semantic-border-layout">
1911
- <div className={creatableToneHintRowClassName}>
1912
- {createHintText ? (
1913
- <span className="text-sm text-semantic-text-muted">
1914
- {createHintText}
1915
- </span>
1916
- ) : (
1917
- <span className="min-w-0 flex-1" />
1779
+ <div className="-mx-0 flex shrink-0 flex-col border-b border-solid border-semantic-border-layout">
1780
+ <div className={creatableToneHintRowClassName}>
1781
+ <input
1782
+ ref={inputRef}
1783
+ type="text"
1784
+ value={inputValue}
1785
+ onChange={(e) => {
1786
+ const raw = e.target.value
1787
+ const sanitized = sanitizeInput ? sanitizeInput(raw) : raw
1788
+ if (sanitizeInput) {
1789
+ if (raw !== sanitized) onInvalidCharacters?.()
1790
+ else onValidInput?.()
1791
+ }
1792
+ setInputValue(
1793
+ maxLengthPerItem != null
1794
+ ? sanitized.slice(0, maxLengthPerItem)
1795
+ : sanitized
1796
+ )
1797
+ }}
1798
+ maxLength={maxLengthPerItem}
1799
+ onKeyDown={handleKeyDown}
1800
+ disabled={disabled}
1801
+ placeholder={panelInputPlaceholder}
1802
+ className="min-w-0 flex-1 bg-transparent text-base text-semantic-text-primary outline-none placeholder:text-semantic-text-muted"
1803
+ role="combobox"
1804
+ aria-expanded={isOpen}
1805
+ aria-controls={listboxId}
1806
+ aria-haspopup="listbox"
1807
+ aria-autocomplete="list"
1808
+ />
1809
+ <button
1810
+ type="button"
1811
+ disabled={disabled || !canShowEnterAffordance}
1812
+ onMouseDown={(e) => {
1813
+ e.preventDefault()
1814
+ }}
1815
+ onClick={() => {
1816
+ if (draftForCreate) addValue(inputValue)
1817
+ }}
1818
+ className={cn(
1819
+ creatableEnterHintKbdClassName,
1820
+ "shrink-0 enabled:cursor-pointer enabled:hover:bg-semantic-bg-hover disabled:opacity-50"
1918
1821
  )}
1919
- <kbd className={creatableEnterHintKbdClassName}>
1920
- Enter \u21B5
1921
- </kbd>
1922
- </div>
1923
- {maxItems != null ? (
1924
- <div className="border-t border-solid border-semantic-border-layout bg-semantic-bg-ui px-4 py-2 text-left text-sm text-semantic-text-muted">
1925
- Max selections allowed: {maxItems}
1926
- </div>
1927
- ) : null}
1822
+ >
1823
+ Enter \u21B5
1824
+ </button>
1928
1825
  </div>
1929
- )}
1826
+ </div>
1827
+
1828
+ <div className="flex flex-col gap-2.5 px-4 pb-4 pt-0">
1829
+ {maxItems != null ? (
1830
+ <p className="m-0 py-1 text-sm text-semantic-text-muted">
1831
+ Max selections allowed: {maxItems}
1832
+ </p>
1833
+ ) : null}
1834
+
1835
+ {value.length > 0 ? (
1836
+ <div
1837
+ className="flex flex-wrap gap-1.5 border-b border-solid border-semantic-border-layout pb-2.5"
1838
+ aria-label="Selected values"
1839
+ >
1840
+ {value.map((val) => (
1841
+ <span
1842
+ key={val}
1843
+ className="inline-flex max-w-full items-center gap-0.5 rounded bg-semantic-bg-ui py-1 pl-2 pr-0.5 text-sm text-semantic-text-primary"
1844
+ >
1845
+ <span className="min-w-0 truncate">
1846
+ {labelForValue(val, options)}
1847
+ </span>
1848
+ <button
1849
+ type="button"
1850
+ data-chip-remove
1851
+ disabled={disabled}
1852
+ aria-label={\`Remove \${labelForValue(val, options)}\`}
1853
+ className={cn(
1854
+ "inline-flex size-6 shrink-0 items-center justify-center rounded text-semantic-text-muted transition-colors",
1855
+ !disabled &&
1856
+ "hover:bg-semantic-bg-hover hover:text-semantic-text-primary"
1857
+ )}
1858
+ onMouseDown={(e) => {
1859
+ e.preventDefault()
1860
+ e.stopPropagation()
1861
+ }}
1862
+ onClick={(e) => {
1863
+ e.stopPropagation()
1864
+ if (!disabled) removeValue(val)
1865
+ }}
1866
+ >
1867
+ <X className="size-3.5" strokeWidth={2} aria-hidden />
1868
+ </button>
1869
+ </span>
1870
+ ))}
1871
+ </div>
1872
+ ) : null}
1930
1873
 
1931
- {filteredPresets.length > 0 && (
1932
- <div className="flex flex-wrap gap-1.5">
1874
+ <div
1875
+ id={listboxId}
1876
+ role="listbox"
1877
+ className="flex flex-wrap gap-1.5"
1878
+ >
1933
1879
  {filteredPresets.map((option) => (
1934
1880
  <button
1935
1881
  key={option.value}
1936
1882
  type="button"
1883
+ role="option"
1884
+ aria-selected={false}
1937
1885
  onMouseDown={(e) => {
1938
1886
  e.preventDefault()
1939
1887
  addValue(option.value)
1940
1888
  }}
1941
- className="inline-flex items-center gap-2.5 whitespace-nowrap rounded border-0 bg-semantic-bg-ui px-2 py-1 text-sm text-semantic-text-primary transition-colors hover:bg-semantic-bg-hover"
1889
+ className="inline-flex items-center gap-2.5 whitespace-nowrap rounded border-0 bg-semantic-bg-ui px-2 py-1 text-left text-sm text-semantic-text-primary transition-colors hover:bg-semantic-bg-hover"
1942
1890
  >
1943
1891
  <Plus
1944
1892
  className="size-2.5 shrink-0 text-semantic-text-muted"
@@ -1949,7 +1897,7 @@ const CreatableMultiSelect = React.forwardRef(
1949
1897
  </button>
1950
1898
  ))}
1951
1899
  </div>
1952
- )}
1900
+ </div>
1953
1901
  </div>
1954
1902
  )}
1955
1903
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myoperator-mcp",
3
- "version": "0.2.259",
3
+ "version": "0.2.261",
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",