{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "slider",
  "type": "registry:ui",
  "title": "Slider",
  "description": "اسلایدر روی <input type=\"range\"> بومی؛ با آرایهٔ دوتایی، بازه با دو دستگیره",
  "dependencies": [
    "@kashi-ui/persian@^1.8.0"
  ],
  "registryDependencies": [
    "https://kashi.sepantapouya.com/r/cx.json",
    "https://kashi.sepantapouya.com/r/kashi-provider.json"
  ],
  "files": [
    {
      "path": "registry/kashi/Slider.tsx",
      "type": "registry:ui",
      "target": "components/kashi/Slider.tsx",
      "content": "\"use client\";\n\nimport { useId, useState, type CSSProperties, type ReactNode } from \"react\";\nimport { formatNumber } from \"@kashi-ui/persian\";\nimport { cx } from \"./cx\";\nimport { useKashi } from \"./KashiProvider\";\n\ntype Val = number | [number, number];\n/** نوع مقدار فقط از value/defaultValue حدس زده شود، نه از onChange؛ وگرنه setState (که تابع هم می‌پذیرد) خطای نوع می‌دهد. با همهٔ نسخه‌های TypeScript کار می‌کند */\ntype NoInferVal<T> = [T][T extends unknown ? 0 : never];\n\nexport interface SliderProps<V extends Val = Val> {\n  label?: ReactNode;\n  /** یک عدد، یا [از، تا] برای بازه */\n  value?: V;\n  defaultValue?: V;\n  onChange?: (value: NoInferVal<V>) => void;\n  /** @default 0 */\n  min?: number;\n  /** @default 100 */\n  max?: number;\n  /** @default 1 */\n  step?: number;\n  /** نمایش مقدار کنار برچسب @default true */\n  showValue?: boolean;\n  /** قالب نمایش؛ پیش‌فرض ارقام فارسی با جداکنندهٔ هزارگان */\n  format?: (n: number) => string;\n  /** برچسب‌های زیر نوار، مثل [0, 50, 100] */\n  marks?: number[];\n  disabled?: boolean;\n  name?: string;\n  className?: string;\n  labels?: { from?: string; to?: string; separator?: string };\n}\n\n/** اسلایدر روی <input type=\"range\"> بومی؛ با آرایهٔ دوتایی، بازه با دو دستگیره */\nexport function Slider<V extends Val>({\n  label, value, defaultValue, onChange, min = 0, max = 100, step = 1, showValue = true,\n  format, marks, disabled, name, className, labels = {},\n}: SliderProps<V>) {\n  const id = useId();\n  const isRange = Array.isArray(value ?? defaultValue);\n  const [inner, setInner] = useState<Val>(defaultValue ?? (isRange ? [min, max] : min));\n  const current = (value ?? inner) as Val;\n  const [lo, hi] = Array.isArray(current) ? current : [min, current];\n  const pct = (n: number) => `${((n - min) / (max - min)) * 100}%`;\n  const { messages: M, digits: D } = useKashi();\n  format ??= (x: number) => formatNumber(x, { digits: D });\n  const { from = M.slider.from, to = M.slider.to, separator = M.common.range } = labels;\n\n  const set = (next: Val) => {\n    if (value === undefined) setInner(next);\n    onChange?.(next as V);\n  };\n\n  const fill = { \"--_from\": isRange ? pct(lo) : \"0%\", \"--_to\": pct(hi) } as CSSProperties;\n  const labelId = `${id}-label`;\n  const input = (which: \"lo\" | \"hi\") => {\n    const v = which === \"lo\" ? lo : hi;\n    return (\n      <input\n        type=\"range\"\n        className=\"k-slider__input\"\n        min={min}\n        max={max}\n        step={step}\n        value={v}\n        disabled={disabled}\n        name={name ? (isRange ? `${name}_${which === \"lo\" ? \"min\" : \"max\"}` : name) : undefined}\n        aria-labelledby={isRange ? undefined : label ? labelId : undefined}\n        aria-label={isRange ? `${which === \"lo\" ? from : to}${typeof label === \"string\" ? ` ${label}` : \"\"}` : undefined}\n        aria-valuetext={format(v)}\n        onChange={(e) => {\n          const n = Number(e.target.value);\n          // دستگیره‌ها از روی هم رد نمی‌شوند\n          if (!isRange) set(n);\n          else set(which === \"lo\" ? [Math.min(n, hi), hi] : [lo, Math.max(n, lo)]);\n        }}\n      />\n    );\n  };\n\n  return (\n    <div className={cx(\"k-slider\", className)} data-range={isRange ? \"\" : undefined}>\n      {(label || showValue) && (\n        <div className=\"k-slider__head\">\n          {label && <span className=\"k-label\" id={labelId}>{label}</span>}\n          {showValue && <span className=\"k-slider__value\" aria-hidden=\"true\">{isRange ? `${format(lo)}${separator}${format(hi)}` : format(hi)}</span>}\n        </div>\n      )}\n      <div className=\"k-slider__track\" style={fill}>\n        <span className=\"k-slider__fill\" aria-hidden=\"true\" />\n        {isRange && input(\"lo\")}\n        {input(\"hi\")}\n      </div>\n      {marks && (\n        <div className=\"k-slider__marks\" aria-hidden=\"true\">\n          {marks.map((m) => <span key={m}>{format(m)}</span>)}\n        </div>\n      )}\n    </div>\n  );\n}\n"
    }
  ]
}