{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "input-with-select",
  "type": "registry:ui",
  "title": "Input With Select",
  "description": "iOS 26 liquid-glass amount input with integrated segmented currency/unit selector and spring-animated knob.",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "path": "registry/ruixenui/input-with-select.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { motion } from \"motion/react\";\n\n/* ── sound ── */\nlet _a: AudioContext, _b: AudioBuffer;\nconst tick = () => {\n  if (typeof window === \"undefined\") return;\n  if (!_a) {\n    _a = new AudioContext();\n    _b = _a.createBuffer(1, (_a.sampleRate * 0.003) | 0, _a.sampleRate);\n    const d = _b.getChannelData(0);\n    for (let i = 0; i < d.length; i++)\n      d[i] = (Math.random() * 2 - 1) * (1 - i / d.length) ** 4;\n  }\n  const s = _a.createBufferSource();\n  s.buffer = _b;\n  const g = _a.createGain();\n  g.gain.value = 0.08;\n  s.connect(g).connect(_a.destination);\n  s.start();\n};\n\n/* ── theme ── */\nconst CSS = `\n.is{\n  --is-glass:linear-gradient(180deg,rgba(255,255,255,0.78),rgba(255,255,255,0.62));\n  --is-border:rgba(0,0,0,0.06);\n  --is-shadow:0 0 1px rgba(0,0,0,0.04),0 2px 8px rgba(0,0,0,0.04),inset 0 1px 0 rgba(255,255,255,0.8);\n  --is-dim:rgba(0,0,0,0.42);\n  --is-mid:rgba(0,0,0,0.55);\n  --is-hi:rgba(0,0,0,0.88);\n  --is-focus:rgba(0,0,0,0.12);\n  --is-sep:rgba(0,0,0,0.06);\n  --is-seg-bg:rgba(0,0,0,0.04);\n  --is-seg-active:rgba(0,0,0,0.07);\n  --is-knob:#fff;\n  --is-knob-border:rgba(0,0,0,0.08);\n  --is-knob-shadow:0 1px 3px rgba(0,0,0,0.12)\n}\n.dark .is,[data-theme=\"dark\"] .is{\n  --is-glass:linear-gradient(180deg,rgba(255,255,255,0.05),rgba(255,255,255,0.02));\n  --is-border:rgba(255,255,255,0.07);\n  --is-shadow:0 1px 3px rgba(0,0,0,0.08),inset 0 1px 0 rgba(255,255,255,0.04);\n  --is-dim:rgba(255,255,255,0.28);\n  --is-mid:rgba(255,255,255,0.5);\n  --is-hi:rgba(255,255,255,0.88);\n  --is-focus:rgba(255,255,255,0.12);\n  --is-sep:rgba(255,255,255,0.06);\n  --is-seg-bg:rgba(255,255,255,0.04);\n  --is-seg-active:rgba(255,255,255,0.09);\n  --is-knob:#fff;\n  --is-knob-border:rgba(255,255,255,0.06);\n  --is-knob-shadow:0 1px 3px rgba(0,0,0,0.15)\n}`;\n\n/* ── types ── */\ninterface Option {\n  value: string;\n  label: string;\n}\n\ninterface InputWithSelectProps {\n  label?: string;\n  placeholder?: string;\n  options?: Option[];\n  defaultOption?: string;\n  defaultValue?: string;\n  onChange?: (value: string, option: string) => void;\n  sound?: boolean;\n  style?: React.CSSProperties;\n}\n\n/* ── component ── */\nexport default function InputWithSelect({\n  label = \"Amount\",\n  placeholder = \"0.00\",\n  options = [\n    { value: \"usd\", label: \"USD\" },\n    { value: \"eur\", label: \"EUR\" },\n    { value: \"inr\", label: \"INR\" },\n  ],\n  defaultOption = \"usd\",\n  defaultValue = \"\",\n  onChange,\n  sound = true,\n  style,\n}: InputWithSelectProps) {\n  const [value, setValue] = React.useState(defaultValue);\n  const [selected, setSelected] = React.useState(defaultOption);\n  const [focused, setFocused] = React.useState(false);\n  const inputRef = React.useRef<HTMLInputElement>(null);\n\n  const activeIdx = options.findIndex((o) => o.value === selected);\n\n  const selectOption = (opt: string) => {\n    if (opt !== selected) {\n      setSelected(opt);\n      if (sound) tick();\n      onChange?.(value, opt);\n    }\n  };\n\n  return (\n    <>\n      <style dangerouslySetInnerHTML={{ __html: CSS }} />\n      <motion.div\n        className=\"is\"\n        initial={{ opacity: 0, y: 8 }}\n        animate={{ opacity: 1, y: 0 }}\n        transition={{ duration: 0.35, ease: [0.25, 0.1, 0.25, 1] }}\n        style={{\n          display: \"inline-flex\",\n          flexDirection: \"column\",\n          gap: 6,\n          ...style,\n        }}\n      >\n        {label && (\n          <span\n            style={{\n              fontSize: 11,\n              fontWeight: 500,\n              letterSpacing: \"0.06em\",\n              textTransform: \"uppercase\" as const,\n              color: \"var(--is-dim)\",\n              userSelect: \"none\" as const,\n              paddingLeft: 4,\n            }}\n          >\n            {label}\n          </span>\n        )}\n\n        {/* glass field */}\n        <div\n          style={{\n            display: \"flex\",\n            alignItems: \"stretch\",\n            borderRadius: 12,\n            background: \"var(--is-glass)\",\n            border: `1px solid ${focused ? \"var(--is-focus)\" : \"var(--is-border)\"}`,\n            boxShadow: \"var(--is-shadow)\",\n            backdropFilter: \"blur(24px)\",\n            WebkitBackdropFilter: \"blur(24px)\",\n            transition: \"border-color 0.2s\",\n            overflow: \"hidden\",\n          }}\n        >\n          {/* input */}\n          <input\n            ref={inputRef}\n            type=\"text\"\n            inputMode=\"decimal\"\n            value={value}\n            onChange={(e) => {\n              setValue(e.target.value);\n              onChange?.(e.target.value, selected);\n            }}\n            onFocus={() => setFocused(true)}\n            onBlur={() => setFocused(false)}\n            placeholder={placeholder}\n            style={{\n              flex: 1,\n              height: 48,\n              padding: \"0 16px\",\n              background: \"transparent\",\n              border: \"none\",\n              outline: \"none\",\n              fontSize: 15,\n              fontWeight: 500,\n              fontVariantNumeric: \"tabular-nums\",\n              color: \"var(--is-hi)\",\n              minWidth: 0,\n            }}\n          />\n\n          {/* separator */}\n          <div\n            style={{\n              width: 1,\n              alignSelf: \"stretch\",\n              background: \"var(--is-sep)\",\n            }}\n          />\n\n          {/* segment control */}\n          <div\n            style={{\n              display: \"flex\",\n              alignItems: \"center\",\n              padding: \"6px\",\n              position: \"relative\",\n            }}\n          >\n            <div\n              style={{\n                display: \"flex\",\n                borderRadius: 8,\n                background: \"var(--is-seg-bg)\",\n                padding: 2,\n                position: \"relative\",\n              }}\n            >\n              {/* active knob */}\n              <motion.div\n                animate={{\n                  x: activeIdx * 100 + \"%\",\n                }}\n                transition={{ type: \"spring\", stiffness: 500, damping: 35 }}\n                style={{\n                  position: \"absolute\",\n                  top: 2,\n                  left: 2,\n                  width: `calc(${100 / options.length}% - ${4 / options.length}px)`,\n                  height: \"calc(100% - 4px)\",\n                  borderRadius: 6,\n                  background: \"var(--is-knob)\",\n                  border: \"1px solid var(--is-knob-border)\",\n                  boxShadow: \"var(--is-knob-shadow)\",\n                }}\n              />\n\n              {options.map((opt) => (\n                <button\n                  key={opt.value}\n                  onClick={() => selectOption(opt.value)}\n                  style={{\n                    position: \"relative\",\n                    zIndex: 1,\n                    padding: \"5px 10px\",\n                    fontSize: 11,\n                    fontWeight: 600,\n                    border: \"none\",\n                    background: \"transparent\",\n                    color:\n                      selected === opt.value ? \"var(--is-hi)\" : \"var(--is-dim)\",\n                    cursor: \"pointer\",\n                    transition: \"color 0.15s\",\n                    whiteSpace: \"nowrap\" as const,\n                  }}\n                >\n                  {opt.label}\n                </button>\n              ))}\n            </div>\n          </div>\n        </div>\n      </motion.div>\n    </>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/ruixen/input-with-select.tsx"
    }
  ]
}