{"version":3,"file":"index.cjs","names":[],"sources":["../src/math.ts","../src/scales.ts","../src/midi.ts","../src/unit.ts"],"sourcesContent":["/**\n * clamp value between min and max\n */\nexport function clamp(value: number, min: number, max: number) {\n  return Math.max(min, Math.min(value, max))\n}\n\n/**\n * Normalize the value from 0 to 1, spreading the range evenly.\n *\n * This is the linear mapping and takes no curve of its own; a `Scale` builds\n * whatever curve it needs on top of it.\n */\nexport function normalizeValue(value: number, min: number, max: number) {\n  if (min >= max) throw new RangeError('requirements: min < max')\n  return clamp((value - min) / (max - min), 0, 1)\n}\n\n/**\n * Convert normalized values back to raw values, spreading the range evenly.\n *\n * The inverse of {@link normalizeValue}.\n */\nexport function rawValue(normalizedValue: number, min: number, max: number) {\n  if (min >= max) throw new RangeError('requirements: min < max')\n  return min + clamp(normalizedValue, 0, 1) * (max - min)\n}\n\n/**\n * Put a value on the grid the caller asked for, rounding a half step upwards.\n *\n * The rounding is done on the quotient rather than by comparing the distance\n * to the two neighbours, because both of those carry error of their own. The\n * quotient is cleared of its artefact first: `0.15 / 0.1` is 1.4999999999999998,\n * and a value sitting exactly on a half step would otherwise fall to whichever\n * side the last bit happened to land on — 0.25 rounded up while 0.15 and 0.35\n * rounded down.\n */\nexport function stepValue(value: number, step: number) {\n  if (step <= 0) throw new RangeError('requirements: step > 0')\n  const quotient = Math.round(toPrecision(value / step))\n  // The product has its own debris to drop: 3141593 * 1e-6 is not 3.141593.\n  const stepped = toPrecision(quotient * step)\n  // Math.round answers -0 for anything in [-0.5, 0), and that reaches the\n  // caller's onChange as a value that prints as 0 but is not it.\n  return stepped === 0 ? 0 : stepped\n}\n\nexport function toFixed(x: number, fractionDigits?: number) {\n  return Number(x.toFixed(fractionDigits))\n}\n\n/**\n * The significant decimal digits a double actually carries. A double holds a\n * little under 16, so anything past this is the binary representation showing\n * through rather than information.\n */\nconst SIGNIFICANT_DIGITS = 15\n\n/**\n * Drop the binary artefact from a computed value.\n *\n * Arithmetic on doubles leaves debris in the last couple of digits, and it\n * accumulates: adding 0.1 to 5 twelve times gives 5.699999999999998 rather\n * than 5.7, and the display of a control shows exactly that. Rounding to the\n * digits a double can carry removes it, and adds nothing back — the value was\n * already the result of a calculation whose own error is that size or larger.\n *\n * This is not the same as rounding to a `step`. {@link stepValue} puts a value\n * on a grid the caller asked for and is a decision about the value; this only\n * removes what was never in the value to begin with.\n *\n * @param significantDigits how many digits to keep. The default is the only\n * one that is purely artefact removal; a smaller number starts discarding real\n * precision.\n *\n * @example\n * toPrecision(5.1 + 0.1) // 5.2, rather than 5.199999999999999\n */\nexport function toPrecision(x: number, significantDigits = SIGNIFICANT_DIGITS) {\n  // Zero has no significant digits to round to, and a non-finite value has no\n  // decimal form to parse back.\n  if (x === 0 || !Number.isFinite(x)) return x\n  const rounded = Number(x.toPrecision(significantDigits))\n  // Rounding up at the very top of the range overflows to Infinity, which is\n  // a worse answer than the artefact.\n  return Number.isFinite(rounded) ? rounded : x\n}\n\nexport function radian(degree: number) {\n  return (Math.PI * degree) / 180\n}\n\nexport function degree(radian: number) {\n  return (180 * radian) / Math.PI\n}\n\nexport function mapValue(\n  value: number,\n  inMin: number,\n  inMax: number,\n  outMin: number,\n  outMax: number,\n) {\n  return ((value - inMin) / (inMax - inMin)) * (outMax - outMin) + outMin\n}\n\nexport function dbToGain(db: number) {\n  return Math.pow(10, db / 20)\n}\n\nexport function gainToDb(gain: number) {\n  return 20 * (Math.log(gain) / Math.LN10)\n}\n","import { clamp, normalizeValue, rawValue } from './math'\n\n/**\n * How a value is distributed across the travel of a control.\n *\n * `normalize` and `denormalize` are inverses of each other: the position is\n * 0 at `min` and 1 at `max`, and everything in between is up to the scale.\n *\n * `min` and `max` are arguments rather than baked into the scale, so a scale\n * holds no state and can be a module level constant. Passing the same object\n * on every render therefore costs nothing.\n *\n * @example\n * ```ts\n * exponentialScale.denormalize(0.5, 20, 20000) // 632.45…\n * ```\n */\nexport interface Scale {\n  /** Value to its position on the travel, 0-1. */\n  normalize: (value: number, min: number, max: number) => number\n  /** Position on the travel, 0-1, back to a value. */\n  denormalize: (position: number, min: number, max: number) => number\n}\n\nfunction assertRange(min: number, max: number) {\n  if (min >= max) throw new RangeError('requirements: min < max')\n}\n\nfunction assertPositiveFinite(value: number, name: string) {\n  if (!Number.isFinite(value) || value <= 0) {\n    throw new RangeError(`${name}: requirements: finite and greater than 0`)\n  }\n}\n\n/**\n * Equal travel gives an equal change in value.\n *\n * The right default for anything already linear in perception: dB values,\n * pan, percentages, MIDI note numbers, semitones.\n */\nexport const linearScale: Scale = {\n  normalize: (value, min, max) => normalizeValue(value, min, max),\n  denormalize: (position, min, max) => rawValue(position, min, max),\n}\n\n/**\n * The power law of JUCE's `NormalisableRange::skew`, applied to `value - min`.\n *\n * Use it when the value has to agree with a JUCE or iPlug2 parameter — a\n * plugin UI in a WebView, say, where the knob must sit exactly where the\n * host's automation curve puts it. {@link skewWithCenterValue} gives the\n * factor that places a chosen value at the middle of the travel.\n *\n * `skew < 1` gives the lower end more travel, `skew > 1` the upper end.\n *\n * For new designs prefer {@link exponentialScale} or {@link curveScale}: the\n * slope of this curve is either zero or infinite at `min`, so the bottom of\n * the range is a dead zone or jumps.\n *\n * @param skew the JUCE skew factor\n */\nexport function skewScale(skew: number): Scale {\n  assertPositiveFinite(skew, 'skewScale')\n  return {\n    // The two expressions JUCE uses, kept verbatim so the numbers agree with\n    // a NormalisableRange: pow() one way, exp(log()) the other.\n    normalize: (value, min, max) =>\n      Math.pow(normalizeValue(value, min, max), skew),\n    denormalize: (position, min, max) =>\n      rawValue(\n        skew === 1\n          ? position\n          : Math.exp(Math.log(clamp(position, 0, 1)) / skew),\n        min,\n        max,\n      ),\n  }\n}\n\n/**\n * The skew factor for {@link skewScale} that puts `centerValue` at the middle\n * of the travel — JUCE's `NormalisableRange::setSkewForCentre`.\n */\nexport function skewWithCenterValue(\n  centerValue: number,\n  min: number,\n  max: number,\n) {\n  assertRange(min, max)\n  if (!(min < centerValue && centerValue < max))\n    throw new RangeError('requirements: min < centerValue < max')\n  return Math.log(0.5) / Math.log((centerValue - min) / (max - min))\n}\n\n/**\n * Equal travel gives an equal *ratio*, so an octave — or a percentage — takes\n * the same distance wherever it falls.\n *\n * The scale for frequency (a filter cutoff over 20-20000 Hz), free running\n * rates, and delay times.\n *\n * Requires `min` and `max` to be non-zero and of the same sign, since no\n * ratio reaches zero or crosses it. Use {@link curveScale} for a range that\n * starts at 0.\n */\nexport const exponentialScale: Scale = {\n  normalize: (value, min, max) => {\n    assertExponentialRange(min, max)\n    // The value is clamped before the logarithm, not after: outside the range\n    // the ratio can be negative, and log() would give NaN rather than a\n    // position to clamp.\n    const start = Math.log(Math.abs(min))\n    const end = Math.log(Math.abs(max))\n    return clamp(\n      (Math.log(Math.abs(clamp(value, min, max))) - start) / (end - start),\n      0,\n      1,\n    )\n  },\n  denormalize: (position, min, max) => {\n    assertExponentialRange(min, max)\n    const start = Math.log(Math.abs(min))\n    const end = Math.log(Math.abs(max))\n    const magnitude = Math.exp(start + (end - start) * clamp(position, 0, 1))\n    return Math.sign(min) * magnitude\n  },\n}\n\nfunction assertExponentialRange(min: number, max: number) {\n  assertRange(min, max)\n  if (min === 0 || max === 0 || Math.sign(min) !== Math.sign(max)) {\n    throw new RangeError(\n      'exponentialScale: requirements: min and max are non-zero and have the same sign',\n    )\n  }\n}\n\n/**\n * An exponential bend that still passes exactly through `min` and `max`, so\n * unlike {@link exponentialScale} it works on a range that starts at 0 or\n * crosses it, and unlike {@link skewScale} its slope is neither zero nor\n * infinite at either end.\n *\n * The general purpose taper, and the same family as the curve of an envelope\n * segment (SuperCollider's `CurveWarp`).\n *\n * - `curve > 0` gives the lower end more travel — envelope times from 0 ms,\n *   delay times, anything that wants fine control near the bottom\n * - `curve < 0` gives the upper end more travel — a volume fader over\n *   -60..+6 dB that should be precise around 0 dB\n * - near 0 it is indistinguishable from {@link linearScale}, and is treated\n *   as linear to avoid dividing by zero\n *\n * {@link curveWithCenterValue} gives the curve that places a chosen value at\n * the middle of the travel.\n *\n * @param curve how hard the curve bends, and in which direction\n */\nexport function curveScale(curve: number): Scale {\n  // Beyond this the flatter half of the curve no longer has enough distinct\n  // double values for normalize and denormalize to remain inverses.\n  if (!Number.isFinite(curve) || Math.abs(curve) > 32) {\n    throw new RangeError(\n      'curveScale: requirements: finite curve from -32 to 32',\n    )\n  }\n  // The two coefficients blow up as the curve flattens: `a` divides by\n  // 1 - e^curve, which goes to 0.\n  if (Math.abs(curve) < 0.001) return linearScale\n\n  return {\n    normalize: (value, min, max) => {\n      assertRange(min, max)\n      const proportion = clamp((value - min) / (max - min), 0, 1)\n      if (proportion === 0 || proportion === 1) return proportion\n      if (curve > 0) {\n        return (\n          1 + Math.log(proportion + (1 - proportion) * Math.exp(-curve)) / curve\n        )\n      }\n      return Math.log1p(proportion * Math.expm1(curve)) / curve\n    },\n    denormalize: (position, min, max) => {\n      assertRange(min, max)\n      const p = clamp(position, 0, 1)\n      if (p === 0) return min\n      if (p === 1) return max\n      const proportion =\n        curve > 0\n          ? (Math.exp(curve * (p - 1)) * (1 - Math.exp(-curve * p))) /\n            (1 - Math.exp(-curve))\n          : Math.expm1(curve * p) / Math.expm1(curve)\n      return min + (max - min) * proportion\n    },\n  }\n}\n\n/**\n * {@link skewScale} mirrored about the middle of the range, so both halves\n * bend the same way — JUCE's `symmetricSkew`.\n *\n * For a bipolar control whose centre matters: detune over -100..+100 cents,\n * or a bipolar filter envelope amount, where the fine adjustment is around 0\n * rather than at either end.\n *\n * `skew < 1` gives the middle more travel, `skew > 1` the two ends.\n *\n * @param skew the JUCE skew factor\n */\nexport function symmetricSkewScale(skew: number): Scale {\n  assertPositiveFinite(skew, 'symmetricSkewScale')\n  return {\n    normalize: (value, min, max) => {\n      assertRange(min, max)\n      const proportion = clamp((value - min) / (max - min), 0, 1)\n      if (skew === 1) return proportion\n      const distanceFromMiddle = 2 * proportion - 1\n      return (\n        (1 +\n          Math.pow(Math.abs(distanceFromMiddle), skew) *\n            Math.sign(distanceFromMiddle)) /\n        2\n      )\n    },\n    denormalize: (position, min, max) => {\n      assertRange(min, max)\n      const p = clamp(position, 0, 1)\n      let distanceFromMiddle = 2 * p - 1\n      if (skew !== 1 && distanceFromMiddle !== 0) {\n        distanceFromMiddle =\n          Math.pow(Math.abs(distanceFromMiddle), 1 / skew) *\n          Math.sign(distanceFromMiddle)\n      }\n      return min + ((max - min) / 2) * (1 + distanceFromMiddle)\n    },\n  }\n}\n\n/**\n * The curve for {@link curveScale} that puts `centerValue` at the middle of\n * the travel — the counterpart of {@link skewWithCenterValue}.\n */\nexport function curveWithCenterValue(\n  centerValue: number,\n  min: number,\n  max: number,\n) {\n  assertRange(min, max)\n  if (!(min < centerValue && centerValue < max)) {\n    throw new RangeError('requirements: min < centerValue < max')\n  }\n  // value(0.5) - min = range / (1 + e^(curve / 2))\n  const proportion = (centerValue - min) / (max - min)\n  return 2 * Math.log(1 / proportion - 1)\n}\n\n/**\n * How a value is scaled: the range it lives in, how it is rounded, and how it\n * is distributed across the travel.\n *\n * `AxisOptions` of `@tremolo-ui/dom` extends this, so a drag and a\n * wheel / keyboard nudge run the same value pipeline.\n */\nexport interface ValueRange {\n  min: number\n  max: number\n  /**\n   * Rounding applied to the value. Left unrounded when omitted.\n   */\n  step?: number\n  /**\n   * How the value is distributed across the travel.\n   *\n   * @default linearScale\n   */\n  scale?: Scale\n}\n","/**\n * Remainder that follows the sign of the divisor, rather than of the dividend.\n *\n * `%` in JavaScript keeps the sign of the left operand, so `-13 % 12` is `-1`\n * and cannot index a 12-element table. Every note here is placed by its\n * position within the octave, and note numbers below C-1 are negative.\n */\nfunction mod(n: number, m: number) {\n  return ((n % m) + m) % m\n}\n\nexport const whiteKeys = ['A', 'B', 'C', 'D', 'E', 'F', 'G'] as const\n\nexport type WhiteKey = (typeof whiteKeys)[number]\n\nexport const noteKeys = [\n  'C',\n  'C#',\n  'D',\n  'D#',\n  'E',\n  'F',\n  'F#',\n  'G',\n  'G#',\n  'A',\n  'A#',\n  'B',\n] as const\n\nexport type NoteKey = (typeof noteKeys)[number]\n\nfunction assertSafeInteger(value: number, name: string) {\n  if (!Number.isSafeInteger(value)) {\n    throw new RangeError(`${name}: requirements: a safe integer`)\n  }\n}\n\nexport function parseNoteName(noteName: string) {\n  const m = noteName.match(/^([a-g])(#{0,2}|b{0,2})(-?\\d+)$/i)\n  if (!m) throw new Error('Invalid note name')\n  const [, letter, accidental, octave] = m\n  const parsedOctave = Number(octave)\n  assertSafeInteger(parsedOctave, 'octave')\n  return {\n    letter: letter.toLocaleUpperCase() as WhiteKey,\n    accidental: accidental as '#' | '##' | 'b' | 'bb' | '',\n    octave: parsedOctave,\n  }\n}\n\n/**\n * Convert noteName to noteNumber\n */\nexport function noteNumber(noteName: string) {\n  const { letter, accidental, octave } = parseNoteName(noteName)\n  const noteIndex = noteKeys.indexOf(letter.toLocaleUpperCase() as NoteKey)\n  const accidentalValue = (accidental[0] === 'b' ? -1 : 1) * accidental.length\n  const result = noteIndex + 12 * (octave + 1) + accidentalValue\n  assertSafeInteger(result, 'note number')\n  return result\n}\n\n/**\n * Convert noteNumber to noteName\n * C-1 = 0\n * G9 = 127\n * @param noteNumber noteNumber\n */\nexport function noteName(noteNumber: number): `${NoteKey}${number}` {\n  assertSafeInteger(noteNumber, 'note number')\n  const noteIndex = mod(noteNumber, 12)\n  const octave = Math.floor(noteNumber / 12) - 1\n  return `${noteKeys[noteIndex]}${octave}`\n}\n\n/**\n * Convert noteNumber to noteKey\n */\nexport function noteKey(noteNumber: number): NoteKey {\n  assertSafeInteger(noteNumber, 'note number')\n  return noteKeys[mod(noteNumber, 12)]\n}\n\n/**\n * @param note noteNumber: 0 ~ 127 or noteName e.g. 'C3'\n */\nexport function isWhiteKey(note: number | string) {\n  const n = typeof note === 'string' ? noteNumber(note) : note\n  assertSafeInteger(n, 'note number')\n  return (\n    mod(n, 12) === 0 ||\n    mod(n, 12) === 2 ||\n    mod(n, 12) === 4 ||\n    mod(n, 12) === 5 ||\n    mod(n, 12) === 7 ||\n    mod(n, 12) === 9 ||\n    mod(n, 12) === 11\n  )\n}\n\n/**\n * @param note noteNumber: 0 ~ 127 or noteName e.g. 'C3'\n */\nexport function isBlackKey(note: number | string) {\n  return !isWhiteKey(note)\n}\n\n/**\n * @param note noteNumber: 0 ~ 127 or noteName e.g. 'C3'\n * @param detune [cent]\n * @param a4 A4 frequency [Hz]\n * @returns frequency [Hz]\n */\nexport function noteToFrequency(note: number | string, detune = 0, a4 = 440) {\n  const n = typeof note === 'string' ? noteNumber(note) : note\n  assertSafeInteger(n, 'note number')\n  return (a4 / 32) * 2 ** ((n - 9 + detune / 100) / 12)\n}\n\n/**\n * Centre of the 14-bit pitch bend range: no bend.\n *\n * The range is not symmetric — 0 is 8192 below centre and 16383 is 8191 above\n * — so a wheel at rest reports exactly this rather than half of the maximum.\n */\nexport const PITCH_BEND_CENTER = 8192\n\n/**\n * A 14-bit pitch bend (0-16383) as -1 to 1, with 0 at rest.\n *\n * Each side of the centre is divided by its own length, since there is one\n * more step below it than above: 0 gives -1 and 16383 gives 1 exactly.\n * Dividing both sides by 8192 would never quite reach 1.\n *\n * @param value pitch bend: 0 ~ 16383\n */\nexport function normalizePitchBend(value: number) {\n  const offset = value - PITCH_BEND_CENTER\n  return offset / (offset < 0 ? PITCH_BEND_CENTER : PITCH_BEND_CENTER - 1)\n}\n\n/**\n * Semitones above the root, for each supported scale.\n *\n * Every entry starts at 0 and stays inside one octave, so a scale is a set of\n * pitch classes rather than a set of notes: {@link inScale} compares against\n * it with the octave taken out.\n *\n * `ionian` and `aeolian` are the same sets as `major` and `naturalMinor`; both\n * spellings are here because both are what someone reaches for depending on\n * whether they are thinking in keys or in modes.\n */\nexport const scaleIntervals = {\n  major: [0, 2, 4, 5, 7, 9, 11],\n  naturalMinor: [0, 2, 3, 5, 7, 8, 10],\n  harmonicMinor: [0, 2, 3, 5, 7, 8, 11],\n  melodicMinor: [0, 2, 3, 5, 7, 9, 11],\n\n  ionian: [0, 2, 4, 5, 7, 9, 11],\n  dorian: [0, 2, 3, 5, 7, 9, 10],\n  phrygian: [0, 1, 3, 5, 7, 8, 10],\n  lydian: [0, 2, 4, 6, 7, 9, 11],\n  mixolydian: [0, 2, 4, 5, 7, 9, 10],\n  aeolian: [0, 2, 3, 5, 7, 8, 10],\n  locrian: [0, 1, 3, 5, 6, 8, 10],\n\n  majorPentatonic: [0, 2, 4, 7, 9],\n  minorPentatonic: [0, 3, 5, 7, 10],\n  blues: [0, 3, 5, 6, 7, 10],\n\n  wholeTone: [0, 2, 4, 6, 8, 10],\n  chromatic: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],\n} as const satisfies Record<string, readonly number[]>\n\nexport type ScaleName = keyof typeof scaleIntervals\n\n/**\n * Whether a note belongs to a scale, regardless of the octave either sits in.\n *\n * @param note noteNumber: 0 ~ 127 or noteName e.g. 'C3'\n * @param root the note the scale is built on, in the same two forms\n *\n * @example\n * ```ts\n * inScale('F#4', 'D3', 'major') // true\n * ```\n */\nexport function inScale(\n  note: number | string,\n  root: number | string,\n  name: ScaleName,\n): boolean {\n  const n = typeof note === 'string' ? noteNumber(note) : note\n  const r = typeof root === 'string' ? noteNumber(root) : root\n  assertSafeInteger(n, 'note number')\n  assertSafeInteger(r, 'root note number')\n  return (scaleIntervals[name] as readonly number[]).includes(mod(n - r, 12))\n}\n\n/**\n * The notes of a scale, ascending from `root`.\n *\n * The octave above the root is not included: ask for more `octaves` instead, so\n * that concatenating the result of two calls does not repeat a note.\n *\n * @param root noteNumber: 0 ~ 127 or noteName e.g. 'C3'\n * @param octaves how many octaves to cover\n *\n * @example\n * ```ts\n * scaleNotes('C3', 'majorPentatonic') // [48, 50, 52, 55, 57]\n * ```\n */\nexport function scaleNotes(\n  root: number | string,\n  name: ScaleName,\n  octaves = 1,\n): number[] {\n  const r = typeof root === 'string' ? noteNumber(root) : root\n  assertSafeInteger(r, 'root note number')\n  if (!Number.isSafeInteger(octaves) || octaves < 0) {\n    throw new RangeError('octaves: requirements: a non-negative safe integer')\n  }\n  const intervals = scaleIntervals[name] as readonly number[]\n  return Array.from({ length: octaves }, (_, octave) =>\n    intervals.map((interval) => r + octave * 12 + interval),\n  ).flat()\n}\n","import { toPrecision } from './math'\n\n/**\n * The SI prefixes {@link unitFormat} chooses between.\n *\n * Deliberately narrower than the full SI set: yocto through yotta are of no\n * use to an audio control, and every extra prefix is one more symbol `parse`\n * has to tell apart from a unit.\n */\nexport type SIPrefix = 'p' | 'n' | 'µ' | 'm' | '' | 'k' | 'M' | 'G'\n\n/** Ordered small to large. The empty symbol is the base unit. */\nconst PREFIXES: readonly [SIPrefix, number][] = [\n  ['p', 1e-12],\n  ['n', 1e-9],\n  ['µ', 1e-6],\n  ['m', 1e-3],\n  ['', 1],\n  ['k', 1e3],\n  ['M', 1e6],\n  ['G', 1e9],\n]\n\nconst PREFIX_SCALE = new Map<string, number>(PREFIXES)\n\n/**\n * Micro is written three ways. `µ` (U+00B5 MICRO SIGN) is what `format`\n * writes and what d3-format uses, `μ` (U+03BC GREEK SMALL LETTER MU) looks\n * identical and is what a Greek keyboard produces, and `u` is what everyone\n * actually types. All three read back the same.\n */\nconst MICRO_ALIASES: Record<string, SIPrefix> = { μ: 'µ', u: 'µ' }\n\nexport interface UnitFormatOptions {\n  /**\n   * The prefix the stored value is already in.\n   *\n   * A control that keeps milliseconds in `value` is `{ base: 'm' }` with a\n   * unit of `'s'`: 1500 then displays as `1.5s`, and `parse` gives 1500 back.\n   *\n   * @default ''\n   */\n  base?: SIPrefix\n  /**\n   * Whether to scale the number and pick a prefix at all.\n   *\n   * Turn it off for anything that is not an SI quantity. dB, %, cents and\n   * semitones do not take prefixes, and `-6dB` read as \"-6 deci-B\" is wrong\n   * rather than merely unusual.\n   *\n   * @default true\n   */\n  prefixes?: boolean\n  /**\n   * Digits after the decimal point. The number is left as-is when omitted.\n   */\n  digits?: number\n  /**\n   * Text placed between the number and the unit.\n   * @default ''\n   */\n  separator?: string\n}\n\n/** The `format` / `parse` pair a `NumberInput` takes. */\nexport interface UnitFormatter {\n  format: (value: number) => string\n  parse: (text: string) => number\n}\n\n/**\n * Divide by a prefix scale without showing the result of doing so in binary.\n *\n * `0.0005 / 1e-6` is 500.00000000000006, and with no `digits` to round it that\n * lands in the input as written.\n */\nfunction scaleBy(value: number, scale: number): number {\n  return toPrecision(value / scale)\n}\n\n/** A number, then whatever followed it. */\nconst NUMBER_THEN_REST =\n  /^([+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:[eE][+-]?\\d+)?)\\s*(.*)$/\n\n/**\n * Build the `format` and `parse` of a unit, as one pair.\n *\n * They are returned together because they have to agree: a `format` that\n * writes `1.23kHz` is only useful next to a `parse` that reads it back as\n * 1230. Spread the result into the input.\n *\n * @example\n * unitFormat('Hz')                                 // 1234 -> '1.23kHz'\n * unitFormat('s', { base: 'm' })                   // value in ms. 1500 -> '1.5s'\n * unitFormat('s', { base: 'm', digits: 2 })        // 1500 -> '1.50s'\n * unitFormat('dB', { prefixes: false, digits: 1 }) // -6.25 -> '-6.3dB'\n *\n * @example\n * <NumberInput.Root {...unitFormat('Hz', { digits: 2 })} value={v} onChange={setV}>\n */\nexport function unitFormat(\n  unit: string,\n  options: UnitFormatOptions = {},\n): UnitFormatter {\n  const { base = '', prefixes = true, digits, separator = '' } = options\n  if (unit === '' && base !== '') {\n    throw new RangeError('unitFormat: base requires a non-empty unit')\n  }\n  const baseScale = PREFIX_SCALE.get(base) ?? 1\n\n  /**\n   * `toFixed` renders anything that rounds to zero from below as `-0`, which\n   * is never what a control should show.\n   */\n  const fixed = (value: number) => {\n    const text = digits !== undefined ? value.toFixed(digits) : String(value)\n    return Number(text) === 0 ? text.replace('-', '') : text\n  }\n\n  if (!prefixes) {\n    // The stored value goes out untouched, so the symbol has to name the unit\n    // it is already in.\n    const symbol = base + unit\n    return {\n      format: (value) =>\n        Number.isFinite(value)\n          ? fixed(value) + separator + symbol\n          : String(value),\n      // Nothing after the number can change the scale, so it is all ignored:\n      // the number in front is the value, half-typed or not.\n      parse: (text) => {\n        const match = text.trim().match(NUMBER_THEN_REST)\n        if (!match) return NaN\n        const value = Number(match[1])\n        return Number.isFinite(value) ? value : NaN\n      },\n    }\n  }\n\n  return {\n    format: (value) => {\n      if (!Number.isFinite(value)) return String(value)\n      const si = value * baseScale\n      // Zero has no magnitude to read, so it stays in the base unit.\n      let index = PREFIXES.findIndex(([, scale]) => scale === 1)\n      if (si !== 0) {\n        // The largest prefix that leaves at least one digit before the point.\n        // Below the smallest prefix the number just gets small: `p` is the\n        // floor, as `G` is the ceiling.\n        const magnitude = Math.abs(si)\n        index = 0\n        for (let i = PREFIXES.length - 1; i >= 0; i--) {\n          if (magnitude >= PREFIXES[i][1]) {\n            index = i\n            break\n          }\n        }\n      }\n      let text = fixed(scaleBy(si, PREFIXES[index][1]))\n      // Rounding can carry the number up out of its own prefix — 999.99Hz at\n      // one digit is 1000.0Hz, which should read 1.0kHz. One step is always\n      // enough, since the carry is at most a factor of ten.\n      if (Math.abs(Number(text)) >= 1000 && index < PREFIXES.length - 1) {\n        index += 1\n        text = fixed(scaleBy(si, PREFIXES[index][1]))\n      }\n      return text + separator + PREFIXES[index][0] + unit\n    },\n\n    parse: (text) => {\n      const match = text.trim().match(NUMBER_THEN_REST)\n      if (!match) return NaN\n      const number = Number(match[1])\n      if (!Number.isFinite(number)) return NaN\n\n      let suffix = match[2].trim()\n      const separatorText = separator.trim()\n      if (separatorText !== '' && suffix.startsWith(separatorText)) {\n        suffix = suffix.slice(separatorText.length).trim()\n      }\n      // A bare number is in the unit the value is stored in, which is what\n      // the input shows once the format is stripped.\n      if (suffix === '') return number\n\n      // The unit symbol is matched first, so a unit that is itself a prefix\n      // letter wins over the prefix reading: `5m` for a unit of `m` is five\n      // metres, not five milli-.\n      let prefix: string | null = null\n      if (unit !== '' && suffix.endsWith(unit)) {\n        prefix = suffix.slice(0, suffix.length - unit.length)\n      } else if (suffix.length <= 1) {\n        prefix = suffix\n      }\n      if (prefix === null) return number\n\n      const normalized = MICRO_ALIASES[prefix] ?? prefix\n      const scale = PREFIX_SCALE.get(normalized)\n      // Unrecognised text after the number is ignored rather than rejected,\n      // so that a half-typed entry still yields the number in front of it.\n      if (scale === undefined) return number\n      return (number * scale) / baseScale\n    },\n  }\n}\n"],"mappings":"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"}