myoperator-mcp 0.2.268 → 0.2.269

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 +119 -101
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1457,7 +1457,7 @@ import { cn } from "@/lib/utils"
1457
1457
  import {
1458
1458
  creatableSelectTriggerVariants,
1459
1459
  creatableEnterHintKbdClassName,
1460
- creatableToneHintRowClassName,
1460
+ creatablePrimaryRoleHintRowClassName,
1461
1461
  } from "./creatable-select"
1462
1462
 
1463
1463
  /** @deprecated Use \`creatableSelectTriggerVariants\` from \`./creatable-select\` \u2014 aliases the same trigger styles as Primary Role. */
@@ -1629,13 +1629,20 @@ const CreatableMultiSelect = React.forwardRef(
1629
1629
  const availablePresets = options.filter(
1630
1630
  (o) => !value.includes(o.value) && !o.disabled
1631
1631
  )
1632
- const filteredPresets = inputValue.trim()
1632
+ const trimmedInput = inputValue.trim()
1633
+ const filteredPresets = trimmedInput
1633
1634
  ? availablePresets.filter((o) =>
1634
- o.label.toLowerCase().includes(inputValue.trim().toLowerCase())
1635
+ o.label.toLowerCase().includes(trimmedInput.toLowerCase())
1635
1636
  )
1636
1637
  : availablePresets
1637
1638
 
1638
- const panelInputPlaceholder = createHintText ?? placeholder
1639
+ const isCustomDraft =
1640
+ trimmedInput.length > 0 &&
1641
+ !options.some(
1642
+ (o) => o.label.toLowerCase() === trimmedInput.toLowerCase()
1643
+ ) &&
1644
+ !value.includes(trimmedInput) &&
1645
+ (maxItems == null || value.length < maxItems)
1639
1646
 
1640
1647
  const summaryTriggerLabel =
1641
1648
  value.length === 0 ? placeholder : selectedSummary
@@ -1662,27 +1669,7 @@ const CreatableMultiSelect = React.forwardRef(
1662
1669
  }}
1663
1670
  >
1664
1671
  <div className="flex min-h-0 min-w-0 flex-1 flex-wrap content-start items-center gap-1.5">
1665
- {triggerDisplay === "summary" ? (
1666
- <span
1667
- className={cn(
1668
- "line-clamp-2 flex-1 text-base",
1669
- value.length === 0
1670
- ? "text-semantic-text-muted"
1671
- : "text-semantic-text-primary"
1672
- )}
1673
- >
1674
- {summaryTriggerLabel}
1675
- </span>
1676
- ) : value.length === 0 ? (
1677
- <span
1678
- className={cn(
1679
- "line-clamp-2 flex-1 text-base",
1680
- "text-semantic-text-muted"
1681
- )}
1682
- >
1683
- {placeholder}
1684
- </span>
1685
- ) : (
1672
+ {triggerDisplay === "chips" &&
1686
1673
  value.map((val) => (
1687
1674
  <span
1688
1675
  key={val}
@@ -1713,9 +1700,45 @@ const CreatableMultiSelect = React.forwardRef(
1713
1700
  <X className="size-3.5" strokeWidth={2} aria-hidden />
1714
1701
  </button>
1715
1702
  </span>
1716
- ))
1717
- )}
1703
+ ))}
1704
+ {triggerDisplay === "summary" && value.length > 0 ? (
1705
+ <span className="line-clamp-2 text-base text-semantic-text-primary">
1706
+ {selectedSummary}
1707
+ </span>
1708
+ ) : null}
1709
+ <input
1710
+ ref={inputRef}
1711
+ type="text"
1712
+ value={inputValue}
1713
+ onChange={(e) => {
1714
+ const raw = e.target.value
1715
+ const sanitized = sanitizeInput ? sanitizeInput(raw) : raw
1716
+ if (sanitizeInput) {
1717
+ if (raw !== sanitized) onInvalidCharacters?.()
1718
+ else onValidInput?.()
1719
+ }
1720
+ setInputValue(
1721
+ maxLengthPerItem != null
1722
+ ? sanitized.slice(0, maxLengthPerItem)
1723
+ : sanitized
1724
+ )
1725
+ }}
1726
+ maxLength={maxLengthPerItem}
1727
+ onKeyDown={handleKeyDown}
1728
+ disabled={disabled}
1729
+ className="min-w-[120px] flex-1 bg-transparent text-base text-semantic-text-primary outline-none placeholder:text-semantic-text-muted"
1730
+ role="combobox"
1731
+ aria-expanded={isOpen}
1732
+ aria-controls={listboxId}
1733
+ aria-haspopup="listbox"
1734
+ aria-autocomplete="list"
1735
+ />
1718
1736
  </div>
1737
+ {maxLengthPerItem != null && showPerItemCharacterCounter ? (
1738
+ <span className="mr-2 mt-1 shrink-0 self-start text-sm text-semantic-text-muted">
1739
+ {inputValue.length}/{maxLengthPerItem}
1740
+ </span>
1741
+ ) : null}
1719
1742
  <ChevronDown
1720
1743
  className="mt-1 size-4 shrink-0 self-start rotate-180 text-semantic-text-muted opacity-70 transition-transform"
1721
1744
  aria-hidden
@@ -1813,104 +1836,94 @@ const CreatableMultiSelect = React.forwardRef(
1813
1836
  </div>
1814
1837
  )}
1815
1838
 
1816
- {/* Dropdown panel: input + limits + presets (Figma: summary row stays above; type-to-create lives here) */}
1839
+ {/* Dropdown panel: decorative hint row, counter, max-selections, presets. Input lives in the trigger above. */}
1817
1840
  {isOpen && (
1818
1841
  <div
1819
1842
  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"
1820
1843
  >
1821
- <div className="-mx-0 flex shrink-0 flex-col border-b border-solid border-semantic-border-layout">
1822
- <div className={creatableToneHintRowClassName}>
1823
- <input
1824
- ref={inputRef}
1825
- type="text"
1826
- value={inputValue}
1827
- onChange={(e) => {
1828
- const raw = e.target.value
1829
- const sanitized = sanitizeInput ? sanitizeInput(raw) : raw
1830
- if (sanitizeInput) {
1831
- if (raw !== sanitized) onInvalidCharacters?.()
1832
- else onValidInput?.()
1833
- }
1834
- setInputValue(
1835
- maxLengthPerItem != null
1836
- ? sanitized.slice(0, maxLengthPerItem)
1837
- : sanitized
1838
- )
1839
- }}
1840
- maxLength={maxLengthPerItem}
1841
- onKeyDown={handleKeyDown}
1842
- disabled={disabled}
1843
- placeholder={panelInputPlaceholder}
1844
- className="min-w-0 flex-1 bg-transparent text-sm text-semantic-text-primary outline-none placeholder:text-semantic-text-muted"
1845
- role="combobox"
1846
- aria-expanded={isOpen}
1847
- aria-controls={listboxId}
1848
- aria-haspopup="listbox"
1849
- aria-autocomplete="list"
1850
- />
1851
- <kbd className={cn(creatableEnterHintKbdClassName, "shrink-0")}>
1844
+ {createHintText ? (
1845
+ <div className={creatablePrimaryRoleHintRowClassName}>
1846
+ <span className="text-sm text-semantic-text-muted">
1847
+ {createHintText}
1848
+ </span>
1849
+ <kbd className={creatableEnterHintKbdClassName}>
1852
1850
  Enter \u21B5
1853
1851
  </kbd>
1854
1852
  </div>
1855
- </div>
1856
-
1857
- <div className="flex flex-col gap-2.5 px-4 pb-4 pt-0">
1858
- {maxItems != null ? (
1859
- <p className="m-0 py-1 text-sm text-semantic-text-muted">
1860
- Max selections allowed: {maxItems}
1861
- </p>
1862
- ) : null}
1853
+ ) : null}
1863
1854
 
1855
+ {(filteredPresets.length > 0 || isCustomDraft) && (
1864
1856
  <div
1865
- id={listboxId}
1866
- role="listbox"
1867
- className="flex flex-wrap gap-1.5"
1857
+ className={cn(
1858
+ "flex flex-col px-4",
1859
+ filteredPresets.length > 0
1860
+ ? "gap-2.5 pb-4 pt-2.5"
1861
+ : "py-1"
1862
+ )}
1868
1863
  >
1869
- {filteredPresets.map((option) => (
1864
+ {maxItems != null && filteredPresets.length > 0 ? (
1865
+ <p className="m-0 text-sm text-semantic-text-muted">
1866
+ Max selections allowed: {maxItems}
1867
+ </p>
1868
+ ) : null}
1869
+
1870
+ {filteredPresets.length > 0 ? (
1871
+ <div
1872
+ id={listboxId}
1873
+ role="listbox"
1874
+ className="flex flex-wrap gap-1.5"
1875
+ >
1876
+ {filteredPresets.map((option) => (
1877
+ <button
1878
+ key={option.value}
1879
+ type="button"
1880
+ role="option"
1881
+ aria-selected={false}
1882
+ onMouseDown={(e) => {
1883
+ e.preventDefault()
1884
+ addValue(option.value)
1885
+ }}
1886
+ 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"
1887
+ >
1888
+ <Plus
1889
+ className="size-2.5 shrink-0 text-semantic-text-muted"
1890
+ strokeWidth={2}
1891
+ aria-hidden
1892
+ />
1893
+ {option.label}
1894
+ </button>
1895
+ ))}
1896
+ </div>
1897
+ ) : null}
1898
+
1899
+ {isCustomDraft ? (
1870
1900
  <button
1871
- key={option.value}
1872
1901
  type="button"
1873
1902
  role="option"
1874
1903
  aria-selected={false}
1875
1904
  onMouseDown={(e) => {
1876
1905
  e.preventDefault()
1877
- addValue(option.value)
1906
+ addValue(inputValue)
1878
1907
  }}
1879
- 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"
1908
+ className="-mx-4 flex w-[calc(100%+2rem)] items-center gap-2 rounded-none px-4 py-2 text-left text-base text-semantic-text-link outline-none transition-colors cursor-pointer select-none hover:bg-semantic-bg-ui"
1880
1909
  >
1881
- <Plus
1882
- className="size-2.5 shrink-0 text-semantic-text-muted"
1883
- strokeWidth={2}
1884
- aria-hidden
1885
- />
1886
- {option.label}
1910
+ Create &ldquo;{trimmedInput}&rdquo;
1887
1911
  </button>
1888
- ))}
1912
+ ) : null}
1889
1913
  </div>
1890
- </div>
1914
+ )}
1891
1915
  </div>
1892
1916
  )}
1893
1917
  </div>
1894
1918
 
1895
- {maxLengthPerItem != null &&
1896
- showPerItemCharacterCounter &&
1897
- isOpen ? (
1898
- <div className="mt-1.5 flex items-center justify-end gap-2">
1899
- <span className="shrink-0 text-sm text-semantic-text-muted">
1900
- {inputValue.length}/{maxLengthPerItem}
1901
- </span>
1919
+ {helperText && !isOpen ? (
1920
+ <div className="mt-1.5 flex items-center gap-1.5">
1921
+ <Info className="size-[18px] shrink-0 text-semantic-text-muted" />
1922
+ <p className="m-0 text-sm text-semantic-text-muted">
1923
+ {helperText}
1924
+ </p>
1902
1925
  </div>
1903
- ) : (
1904
- helperText &&
1905
- !isOpen && (
1906
- <div className="mt-1.5 flex items-center gap-1.5">
1907
- <Info className="size-[18px] shrink-0 text-semantic-text-muted" />
1908
- <p className="m-0 text-sm text-semantic-text-muted">
1909
- {helperText}
1910
- </p>
1911
- </div>
1912
- )
1913
- )}
1926
+ ) : null}
1914
1927
  </div>
1915
1928
  )
1916
1929
  }
@@ -1988,7 +2001,7 @@ export interface CreatableSelectProps
1988
2001
  creatableHint?: string
1989
2002
  /** Whether the select is disabled */
1990
2003
  disabled?: boolean
1991
- /** Max character length for the value (enforced when open and when creating) */
2004
+ /** Max character length for the value (enforced when open and when creating). When set, an in-field \`current/max\` counter renders before the chevron while the dropdown is open. */
1992
2005
  maxLength?: number
1993
2006
  /**
1994
2007
  * When set, combobox input is transformed (e.g. strip invalid characters).
@@ -2202,6 +2215,11 @@ const CreatableSelect = React.forwardRef(
2202
2215
  role="combobox"
2203
2216
  aria-autocomplete="list"
2204
2217
  />
2218
+ {maxLength != null ? (
2219
+ <span className="mr-2 shrink-0 text-sm text-semantic-text-muted">
2220
+ {search.length}/{maxLength}
2221
+ </span>
2222
+ ) : null}
2205
2223
  <ChevronDown className="size-4 text-semantic-text-muted opacity-70 shrink-0 rotate-180 transition-transform" />
2206
2224
  </div>
2207
2225
  ) : (
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myoperator-mcp",
3
- "version": "0.2.268",
3
+ "version": "0.2.269",
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",