@tremolo-ui/functions 0.5.0 → 0.6.0

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.
package/dist/index.d.ts CHANGED
@@ -16,8 +16,45 @@ declare function normalizeValue(value: number, min: number, max: number): number
16
16
  * The inverse of {@link normalizeValue}.
17
17
  */
18
18
  declare function rawValue(normalizedValue: number, min: number, max: number): number;
19
+ /**
20
+ * Put a value on the grid the caller asked for, rounding a half step upwards.
21
+ *
22
+ * The rounding is done on the quotient rather than by comparing the distance
23
+ * to the two neighbours, because both of those carry error of their own. The
24
+ * quotient is cleared of its artefact first: `0.15 / 0.1` is 1.4999999999999998,
25
+ * and a value sitting exactly on a half step would otherwise fall to whichever
26
+ * side the last bit happened to land on — 0.25 rounded up while 0.15 and 0.35
27
+ * rounded down.
28
+ */
19
29
  declare function stepValue(value: number, step: number): number;
20
30
  declare function toFixed(x: number, fractionDigits?: number): number;
31
+ /**
32
+ * The significant decimal digits a double actually carries. A double holds a
33
+ * little under 16, so anything past this is the binary representation showing
34
+ * through rather than information.
35
+ */
36
+ declare const SIGNIFICANT_DIGITS = 15;
37
+ /**
38
+ * Drop the binary artefact from a computed value.
39
+ *
40
+ * Arithmetic on doubles leaves debris in the last couple of digits, and it
41
+ * accumulates: adding 0.1 to 5 twelve times gives 5.699999999999998 rather
42
+ * than 5.7, and the display of a control shows exactly that. Rounding to the
43
+ * digits a double can carry removes it, and adds nothing back — the value was
44
+ * already the result of a calculation whose own error is that size or larger.
45
+ *
46
+ * This is not the same as rounding to a `step`. {@link stepValue} puts a value
47
+ * on a grid the caller asked for and is a decision about the value; this only
48
+ * removes what was never in the value to begin with.
49
+ *
50
+ * @param significantDigits how many digits to keep. The default is the only
51
+ * one that is purely artefact removal; a smaller number starts discarding real
52
+ * precision.
53
+ *
54
+ * @example
55
+ * toPrecision(5.1 + 0.1) // 5.2, rather than 5.199999999999999
56
+ */
57
+ declare function toPrecision(x: number, significantDigits?: number): number;
21
58
  declare function integerPart(x: number | string): string | undefined;
22
59
  declare function decimalPart(x: number | string): string | undefined;
23
60
  declare function radian(degree: number): number;
@@ -26,11 +63,76 @@ declare function mapValue(value: number, inMin: number, inMax: number, outMin: n
26
63
  declare function dbToGain(db: number): number;
27
64
  declare function gainToDb(gain: number): number;
28
65
  //#endregion
29
- //#region src/types.d.ts
66
+ //#region src/modifiers.d.ts
30
67
  /**
31
68
  * Options for setting the amount of keyboard and mouse wheel changes.
32
69
  */
33
- type InputEventOption = ['normalized' | 'raw', number];
70
+ type InputEventOption = readonly ['normalized' | 'raw', number];
71
+ /**
72
+ * A modifier key that can carry an amount of its own.
73
+ *
74
+ * `ctrl` and `meta` are kept apart rather than folded into one "command" key:
75
+ * a plugin UI that mirrors a desktop host usually wants the same physical key
76
+ * on every platform, not the platform's own convention.
77
+ */
78
+ type Modifier = 'shift' | 'alt' | 'ctrl' | 'meta';
79
+ /** The modifier flags of a `WheelEvent` or a `KeyboardEvent`. */
80
+ interface ModifierState {
81
+ shiftKey: boolean;
82
+ altKey: boolean;
83
+ ctrlKey: boolean;
84
+ metaKey: boolean;
85
+ }
86
+ /** One setting per modifier key, with `default` for none of them. */
87
+ type ModifierSetting = number | InputEventOption;
88
+ type ModifierMap<T extends ModifierSetting> = {
89
+ default: T;
90
+ } & Partial<Record<Modifier, T>>;
91
+ /**
92
+ * A single setting, or one per modifier key.
93
+ *
94
+ * @example
95
+ * ['raw', 1]
96
+ * { default: ['raw', 1], shift: ['raw', 0.1] }
97
+ */
98
+ type ModifierValue<T extends ModifierSetting> = T | ModifierMap<T>;
99
+ interface SelectedInputEvent {
100
+ option: InputEventOption;
101
+ /** Which modifier entry was chosen, or `null` for `default`. */
102
+ modifier: Modifier | null;
103
+ }
104
+ /**
105
+ * Pick the setting that applies, given the modifier keys being held.
106
+ *
107
+ * @example
108
+ * selectModifier({ default: 1, shift: 0.1 }, event)
109
+ */
110
+ declare function selectModifier<T extends ModifierSetting>(options: ModifierValue<T>, modifiers?: ModifierState): {
111
+ value: T;
112
+ modifier: Modifier | null;
113
+ };
114
+ /**
115
+ * Turn every entry of a setting into another kind of setting, keeping which
116
+ * modifier each belongs to.
117
+ *
118
+ * A drag sensitivity is a number and a keyboard amount is a tuple, but the two
119
+ * describe the same thing from the caller's side. This carries one over to the
120
+ * other so that a component can hand a sensitivity to {@link applyDelta}
121
+ * without unpicking the modifier map itself — which matters, since naming a
122
+ * modifier is also what takes `step` out of the pipeline.
123
+ *
124
+ * @example
125
+ * mapModifier({ default: 1, shift: 0.1 }, (f) => ['raw', step * f])
126
+ * // { default: ['raw', 1], shift: ['raw', 0.1] }
127
+ */
128
+ declare function mapModifier<T extends ModifierSetting, U extends ModifierSetting>(options: ModifierValue<T>, fn: (value: T) => U): ModifierValue<U>;
129
+ /**
130
+ * Pick the amount that applies, given the modifier keys being held.
131
+ *
132
+ * @example
133
+ * selectInputEvent({ default: ['raw', 1], shift: ['raw', 0.1] }, event)
134
+ */
135
+ declare function selectInputEvent(options: ModifierValue<InputEventOption>, modifiers?: ModifierState): SelectedInputEvent;
34
136
  //#endregion
35
137
  //#region src/scales.d.ts
36
138
  /**
@@ -166,16 +268,18 @@ interface ValueRange {
166
268
  * @param direction which way, and how many times, to apply the option. The
167
269
  * size of one step is `option[1]`, so this is normally `1` or `-1`.
168
270
  *
271
+ * @param modifiers the event, for `options` that name a modifier key. See
272
+ * {@link selectInputEvent}.
273
+ *
169
274
  * @example
170
275
  * // ArrowDown on a slider whose keyboard option is ['raw', 1]
171
276
  * applyDelta(value, -1, keyboard, { min, max, step, scale })
277
+ *
278
+ * @example
279
+ * // Shift+ArrowDown, where `keyboard` is { default: …, shift: ['raw', 0.1] }
280
+ * applyDelta(value, -1, keyboard, range, event)
172
281
  */
173
- declare function applyDelta(value: number, direction: number, [mode, amount]: InputEventOption, {
174
- min,
175
- max,
176
- step,
177
- scale
178
- }: ValueRange): number;
282
+ declare function applyDelta(value: number, direction: number, options: ModifierValue<InputEventOption>, { min, max, step, scale }: ValueRange, modifiers?: ModifierState): number;
179
283
  //#endregion
180
284
  //#region src/midi.d.ts
181
285
  declare const whiteKeys: readonly ["A", "B", "C", "D", "E", "F", "G"];
@@ -341,52 +445,69 @@ declare function noteAt(x: number, y: number, height: number, layout: PianoLayou
341
445
  //#endregion
342
446
  //#region src/unit.d.ts
343
447
  /**
344
- * Units a value can be displayed in, as `[symbol, scale]` pairs ordered from
345
- * the smallest scale up. A value is shown in the largest unit that does not
346
- * exceed it.
448
+ * The SI prefixes {@link unitFormat} chooses between.
347
449
  *
348
- * @example
349
- * [['Hz', 1], ['kHz', 1000]]
350
- * [['ms', 1], ['s', 1000]]
351
- */
352
- type Units = [string, number][];
353
- /**
354
- * Pick the unit a value is displayed in: the largest one whose scale does not
355
- * exceed the magnitude of the value.
450
+ * Deliberately narrower than the full SI set: yocto through yotta are of no
451
+ * use to an audio control, and every extra prefix is one more symbol `parse`
452
+ * has to tell apart from a unit.
356
453
  */
357
- declare function selectUnit(units: Units, value: number): [string, number];
454
+ type SIPrefix = 'p' | 'n' | 'µ' | 'm' | '' | 'k' | 'M' | 'G';
455
+ interface UnitFormatOptions {
456
+ /**
457
+ * The prefix the stored value is already in.
458
+ *
459
+ * A control that keeps milliseconds in `value` is `{ base: 'm' }` with a
460
+ * unit of `'s'`: 1500 then displays as `1.5s`, and `parse` gives 1500 back.
461
+ *
462
+ * @default ''
463
+ */
464
+ base?: SIPrefix;
465
+ /**
466
+ * Whether to scale the number and pick a prefix at all.
467
+ *
468
+ * Turn it off for anything that is not an SI quantity. dB, %, cents and
469
+ * semitones do not take prefixes, and `-6dB` read as "-6 deci-B" is wrong
470
+ * rather than merely unusual.
471
+ *
472
+ * @default true
473
+ */
474
+ prefixes?: boolean;
475
+ /**
476
+ * Digits after the decimal point. The number is left as-is when omitted.
477
+ */
478
+ digits?: number;
479
+ /**
480
+ * Text placed between the number and the unit.
481
+ * @default ''
482
+ */
483
+ separator?: string;
484
+ }
485
+ /** The `format` / `parse` pair a `NumberInput` takes. */
486
+ interface UnitFormatter {
487
+ format: (value: number) => string;
488
+ parse: (text: string) => number;
489
+ }
358
490
  /**
359
- * Render a value as text, in the unit that suits its magnitude.
491
+ * Build the `format` and `parse` of a unit, as one pair.
360
492
  *
361
- * @param units a single symbol appended as-is, or a list to choose from.
362
- * @param digit digits after the decimal point. Left as-is when omitted.
493
+ * They are returned together because they have to agree: a `format` that
494
+ * writes `1.23kHz` is only useful next to a `parse` that reads it back as
495
+ * 1230. Spread the result into the input.
363
496
  *
364
497
  * @example
365
- * formatValue(1234, [['Hz', 1], ['kHz', 1000]], 2) // '1.23kHz'
366
- * formatValue(1.5, 'Hz') // '1.5Hz'
367
- */
368
- declare function formatValue(value: number, units?: string | Units, digit?: number): string;
369
- /**
370
- * Read a value back out of text, undoing the scaling of {@link formatValue}.
371
- *
372
- * With a list of units the text has to be a number followed by an optional
373
- * unit and nothing else, since the unit decides the scale; anything else reads
374
- * as 0. With a single unit, or none, the first number found anywhere in the
375
- * text is taken, so a half-typed entry still yields something.
498
+ * unitFormat('Hz') // 1234 -> '1.23kHz'
499
+ * unitFormat('s', { base: 'm' }) // value in ms. 1500 -> '1.5s'
500
+ * unitFormat('s', { base: 'm', digits: 2 }) // 1500 -> '1.50s'
501
+ * unitFormat('dB', { prefixes: false, digits: 1 }) // -6.25 -> '-6.3dB'
376
502
  *
377
503
  * @example
378
- * parseValue('1.23kHz', [['Hz', 1], ['kHz', 1000]]) // 1230
379
- * parseValue('4abc') // 4
504
+ * <NumberInput.Root {...unitFormat('Hz', { digits: 2 })} value={v} onChange={setV}>
380
505
  */
381
- declare function parseValue(text: string, units?: string | Units): number;
506
+ declare function unitFormat(unit: string, options?: UnitFormatOptions): UnitFormatter;
382
507
  //#endregion
383
508
  //#region src/util.d.ts
384
- type Operator = '+' | '-' | '*' | '/';
385
- declare function styleHelper(value: string | number): string;
386
- declare function styleHelper(value: string | number, op: Operator, influencer?: number): string;
387
- declare function isEmpty(obj: object): boolean;
388
509
  declare function mod(n: number, m: number): number;
389
510
  declare function xor(a?: boolean, b?: boolean): boolean;
390
511
  //#endregion
391
- export { type InputEventOption, type NoteKey, type NoteRange, type PianoLayout, type Scale, type ScaleName, type Units, type ValueRange, type WhiteKey, applyDelta, blackKeyWidth, clamp, curveScale, curveWithCenterValue, dbToGain, decimalPart, degree, exponentialScale, formatValue, gainToDb, getNoteRangeArray, inScale, integerPart, isBlackKey, isEmpty, isWhiteKey, linearScale, mapValue, mod, normalizeValue, noteAt, noteKey, noteKeys, noteName, noteNumber, notePosition, noteToFrequency, parseNoteName, parseValue, pianoWidth, radian, rawValue, scaleIntervals, scaleNotes, selectUnit, skewScale, skewWithCenterValue, stepValue, styleHelper, symmetricSkewScale, toFixed, whiteKeys, xor };
512
+ export { type InputEventOption, type Modifier, type ModifierMap, type ModifierState, type ModifierValue, type NoteKey, type NoteRange, type PianoLayout, SIGNIFICANT_DIGITS, type SIPrefix, type Scale, type ScaleName, type SelectedInputEvent, type UnitFormatOptions, type UnitFormatter, type ValueRange, type WhiteKey, applyDelta, blackKeyWidth, clamp, curveScale, curveWithCenterValue, dbToGain, decimalPart, degree, exponentialScale, gainToDb, getNoteRangeArray, inScale, integerPart, isBlackKey, isWhiteKey, linearScale, mapModifier, mapValue, mod, normalizeValue, noteAt, noteKey, noteKeys, noteName, noteNumber, notePosition, noteToFrequency, parseNoteName, pianoWidth, radian, rawValue, scaleIntervals, scaleNotes, selectInputEvent, selectModifier, skewScale, skewWithCenterValue, stepValue, symmetricSkewScale, toFixed, toPrecision, unitFormat, whiteKeys, xor };
392
513
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/math.ts","../src/types.ts","../src/scales.ts","../src/midi.ts","../src/piano.ts","../src/unit.ts","../src/util.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/math.ts","../src/modifiers.ts","../src/scales.ts","../src/midi.ts","../src/piano.ts","../src/unit.ts","../src/util.ts"],"mappings":";;;;iBAGgB,MAAM,eAAe,aAAa;;;;;;;iBAUlC,eAAe,eAAe,aAAa;;;;;;iBAU3C,SAAS,yBAAyB,aAAa;;;;;;;;;;;iBAe/C,UAAU,eAAe;iBAUzB,QAAQ,WAAW;;;;;;cAStB;;;;;;;;;;;;;;;;;;;;;iBAsBG,YAAY,WAAW;iBAUvB,YAAY;iBAOZ,YAAY;iBAIZ,OAAO;iBAIP,OAAO;iBAIP,SACd,eACA,eACA,eACA,gBACA;iBAKc,SAAS;iBAIT,SAAS;;;;;;KCvHb;;;;;;;;KASA;;UAGK;EACf;EACA;EACA;EACA;;;KAIG,2BAA2B;KAEpB,YAAY,UAAU;EAAqB,SAAS;IAAM,QACpE,OAAO,UAAU;;;;;;;;KAUP,cAAc,UAAU,mBAAmB,IAAI,YAAY;UAEtD;EACf,QAAQ;;EAER,UAAU;;;;;;;;iBAsCI,eAAe,UAAU,iBACvC,SAAS,cAAc,IACvB,YAAY;EACT,OAAO;EAAG,UAAU;;;;;;;;;;;;;;;;iBAiCT,YACd,UAAU,iBACV,UAAU,iBACV,SAAS,cAAc,IAAI,KAAK,OAAO,MAAM,IAAI,cAAc;;;;;;;iBAgBjD,iBACd,SAAS,cAAc,mBACvB,YAAY,gBACX;;;;;;;;;;;;;;;;;;UClHc;;EAEf,YAAY,eAAe,aAAa;;EAExC,cAAc,kBAAkB,aAAa;;;;;;;;cAmBlC,aAAa;;;;;;;;;;;;;;;;;iBAqBV,UAAU,eAAe;;;;;iBAsBzB,oBACd,qBACA,aACA;;;;;;;;;;;;cAmBW,kBAAkB;;;;;;;;;;;;;;;;;;;;;;iBAqDf,WAAW,gBAAgB;;;;;;;;;;;;;iBAmD3B,mBAAmB,eAAe;;;;;iBAiClC,qBACd,qBACA,aACA;;;;;;;;UAkBe;EACf;EACA;;;;EAIA;;;;;;EAMA,QAAQ;;;;;;;;;;;;;;;;;;;;;;;iBAwBM,WACd,eACA,mBACA,SAAS,cAAc,qBACrB,KAAK,KAAK,MAAM,SAAuB,YACzC,YAAY;;;cCpTD;KAED,mBAAmB;cAElB;KAeD,kBAAkB;iBAQd,cAAc;EAOY,QAAA;EACZ;;;;;;iBAQd,WAAW;;;;;;;iBAeX,SAAS,wBAAwB;;;;iBAUjC,QAAQ,qBAAqB;;;;iBAQ7B,WAAW;;;;iBAiBX,WAAW;;;;;;;iBAUX,gBAAgB,uBAAuB,iBAAY;;;;;;;;;;;;cAiBtD;;;;;;;;;;;;;;;;;;KAsBD,yBAAyB;;;;;;;;;;;;iBAarB,QACd,uBACA,uBACA,MAAM;;;;;;;;;;;;;;;iBAuBQ,WACd,uBACA,MAAM,WACN;;;KCxLU;EACV;EACA;;;;;iBAMc,kBAAkB,WAAW;;;;;;;UAa5B;EACf,WAAW;;EAGX;;;;;;;EAQA;;;;;;EAOA;;;;;;EAOA;;;iBA8Bc,cAAc,QAAQ;;iBA0CtB,WAAW,QAAQ;;;;;;;;iBAYnB,aAAa,cAAc,QAAQ;;;;;;;;;;;;iBAenC,OACd,WACA,WACA,gBACA,QAAQ;;;;;;;;;;KC/IE;UAwBK;;;;;;;;;EASf,OAAO;;;;;;;;;;EAUP;;;;EAIA;;;;;EAKA;;;UAIe;EACf,SAAS;EACT,QAAQ;;;;;;;;;;;;;;;;;;iBAiCM,WACd,cACA,UAAS,oBACR;;;iBCvGa,IAAI,WAAW;iBAIf,IAAI,aAAW"}