@uni-design-system/uni-angular 9.0.0 → 10.0.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.
@@ -187,6 +187,382 @@ declare const splitDateTime: (value?: UniDateTime) => {
187
187
  /** One combined value only when both parts are present. */
188
188
  declare const joinDateTime: (date?: UniDate, time?: UniTime) => UniDateTime | undefined;
189
189
 
190
+ /**
191
+ * Canonical numeric value shapes shared by `uni-number-input`,
192
+ * `uni-quantity-stepper`, `uni-number-range-input` and `uni-slider`.
193
+ *
194
+ * The components' internal source of truth is a **canonical decimal string** —
195
+ * optional sign, digits, an optional `.`, no grouping and no affix:
196
+ * `'-1234.56'`. The bound `number` is its projection, emitted on commit.
197
+ *
198
+ * Nothing numeric passes through a float, because floats give wrong answers to
199
+ * questions people ask of money: `0.1 + 0.2` is `0.30000000000000004`, and
200
+ * `(1.15).toFixed(1)` is `'1.1'` — 1.15 is really 1.1499999999999999, so the
201
+ * platform rounds a tie that isn't there. See `decimal.helper.ts`.
202
+ */
203
+ /** A start–end numeric range. Either end alone is a valid value. */
204
+ interface UniNumberRange {
205
+ start?: number;
206
+ end?: number;
207
+ }
208
+ /**
209
+ * How a tie is resolved when rounding to a fraction-digit count.
210
+ *
211
+ * `half-up` is the invoice default (ties away from zero: `1.15` → `1.2`);
212
+ * `half-even` is banker's rounding, which removes the upward bias across a
213
+ * column of figures (`1.25` → `1.2`, `1.35` → `1.4`).
214
+ */
215
+ type UniRoundingMode = 'half-up' | 'half-even' | 'ceil' | 'floor' | 'trunc';
216
+ /** Format archetype. Supplies decimals, grouping, affix and `inputmode`. */
217
+ type UniNumberPreset = 'decimal' | 'integer' | 'currency' | 'percent';
218
+ /**
219
+ * Thousands-separator policy, mapped onto `Intl`'s `useGrouping`.
220
+ *
221
+ * `min2` — the default — groups only from five integer digits, so a year
222
+ * renders `2026` rather than `2,026` while a price still renders `10,000`.
223
+ */
224
+ type UniNumberGrouping = 'auto' | 'always' | 'min2' | false;
225
+ /** Why a typed commit was refused. The raw text stays in the field. */
226
+ type UniNumberRejectReason = 'unparseable' | 'min' | 'max' | 'step' | 'precision' | 'not-integer';
227
+ /** Fences and snap grid for `stepDecimal`. */
228
+ interface UniNumberStepConfig {
229
+ /** Grid spacing. Steps land on `origin + n · step`. Default `1`. */
230
+ step?: number | string;
231
+ min?: number | string;
232
+ max?: number | string;
233
+ /**
234
+ * Snap-grid anchor. `'min'` matches the platform's `<input type="number">`
235
+ * (a field with `min=5, step=10` steps 5 → 15 → 25); `'zero'` anchors the
236
+ * grid at 0 regardless of the fence.
237
+ */
238
+ stepOrigin?: 'min' | 'zero';
239
+ /**
240
+ * Cycle past a fence instead of stopping at it — for genuinely cyclic
241
+ * fields only (23 → 0 hours, 359 → 0 degrees). Needs both `min` and `max`.
242
+ */
243
+ wrap?: boolean;
244
+ }
245
+ /** The outcome of clamping a value to its fences. */
246
+ interface UniNumberClamp {
247
+ /** The clamped canonical decimal. */
248
+ value: string;
249
+ /** Which fence was hit, or `null` when the value was already in range. */
250
+ hit: 'min' | 'max' | null;
251
+ }
252
+ /**
253
+ * Separators, currency placement and fraction digits read out of `Intl` for a
254
+ * locale. Nothing here is hardcoded per language — `1.234,56` is German input,
255
+ * not malformed input, and only the locale knows that.
256
+ */
257
+ interface UniLocaleNumberParts {
258
+ /** Thousands separator: `','` (en), `'.'` (de), a narrow no-break space (fr). */
259
+ group: string;
260
+ /** Decimal separator: `'.'` (en), `','` (de). */
261
+ decimal: string;
262
+ /** Currency symbol, when a currency was given: `'$'`, `'€'`, `'¥'`. */
263
+ currencySymbol: string;
264
+ /** True when the locale writes the symbol before the number. */
265
+ currencyLeading: boolean;
266
+ /** Fraction digits `Intl` uses for the currency — JPY 0, USD 2. */
267
+ currencyDecimals: number;
268
+ }
269
+ /**
270
+ * What a component knows about its own formatting, before resolution. Mirrors
271
+ * the component inputs so a control can forward its signals almost verbatim.
272
+ */
273
+ interface UniNumberFormatConfig {
274
+ preset?: UniNumberPreset;
275
+ /** ISO 4217 code, e.g. `'USD'`. Implies the `currency` preset. */
276
+ currency?: string;
277
+ /** BCP 47 tag. Defaults to `'en-US'`; components pass the document's. */
278
+ locale?: string;
279
+ /** Fixed fraction digits, or `[min, max]`. Overrides the preset. */
280
+ decimals?: number | [min: number, max: number];
281
+ grouping?: UniNumberGrouping;
282
+ /** Static adornment, rendered outside the editable text. */
283
+ prefix?: string;
284
+ suffix?: string;
285
+ roundingMode?: UniRoundingMode;
286
+ /**
287
+ * The model is a fraction: `0.15` displays as `15`. Without it, a percent
288
+ * field displays `15` for `15` and never divides behind the user's back.
289
+ */
290
+ valueIsFraction?: boolean;
291
+ /** Escape hatch, merged over the preset. Only `notation` is read today. */
292
+ numberFormat?: Intl.NumberFormatOptions;
293
+ /** Read only to decide `inputmode` — a field that can go negative needs `-`. */
294
+ min?: number;
295
+ /** Spoken long form of an abbreviated suffix, for `aria-valuetext`. */
296
+ unitAnnouncement?: string;
297
+ }
298
+ /** A format config with every preset and locale default filled in. */
299
+ interface UniResolvedNumberFormat {
300
+ locale: string;
301
+ parts: UniLocaleNumberParts;
302
+ prefix: string;
303
+ suffix: string;
304
+ minimumFractionDigits: number;
305
+ maximumFractionDigits: number;
306
+ grouping: UniNumberGrouping;
307
+ /** `1.5k` in, `1.5K` out. */
308
+ compact: boolean;
309
+ /** Fraction entry is refused outright rather than rounded away. */
310
+ isInteger: boolean;
311
+ /** Display value is the model value × `10^shift`. */
312
+ shift: number;
313
+ roundingMode: UniRoundingMode;
314
+ /** `numeric` only when negatives and decimals are both impossible. */
315
+ inputMode: 'decimal' | 'numeric';
316
+ unitAnnouncement?: string;
317
+ }
318
+ /**
319
+ * The outcome of reading a user's text. Refused text is never swallowed: the
320
+ * caller keeps it in the field and flags it, so nobody loses their work to a
321
+ * silently emptied box.
322
+ */
323
+ type UniNumberParseResult = {
324
+ status: 'empty';
325
+ } | {
326
+ status: 'ok';
327
+ value: string;
328
+ viaExpression: boolean;
329
+ } | {
330
+ status: 'error';
331
+ reason: UniNumberRejectReason;
332
+ };
333
+
334
+ /**
335
+ * Exact decimal arithmetic over canonical decimal strings, using scaled
336
+ * `BigInt`s. No number library — `BigInt` is the platform's own exact integer
337
+ * type, and every operation here is integer arithmetic with a remembered
338
+ * decimal point.
339
+ *
340
+ * A **canonical decimal** is `/^-?\d+(\.\d+)?$/`: optional sign, digits, an
341
+ * optional fraction, no grouping, no affix, no exponent. Everything in this
342
+ * file takes and returns that shape.
343
+ *
344
+ * Why not floats, concretely:
345
+ *
346
+ * ```
347
+ * 0.1 + 0.2 → 0.30000000000000004 // IEEE 754
348
+ * scaled: 1n + 2n = 3n, ÷10 → '0.3' // here
349
+ *
350
+ * (1.15).toFixed(1) → '1.1' // 1.15 is really 1.1499999999999999,
351
+ * // so the platform breaks a tie that
352
+ * // does not exist in the decimal value
353
+ * roundDecimal('1.15', 1) → '1.2' // what an invoice expects
354
+ * ```
355
+ *
356
+ * The scale (fraction-digit count) is carried alongside the integer rather
357
+ * than inferred, so `'1.50'` and `'1.5'` compare equal but a value's own
358
+ * precision survives a round trip.
359
+ */
360
+
361
+ /** True when `text` is already a canonical decimal (leading/trailing space allowed). */
362
+ declare const isCanonicalDecimal: (text: string) => boolean;
363
+ /** Fraction-digit count. `'1.250'` → 3, `'12'` → 0, `'5.'` → 0. */
364
+ declare const decimalScale: (value: string) => number;
365
+ /**
366
+ * Canonical decimal → integer scaled by `10^scale`. Fraction digits beyond
367
+ * `scale` are truncated, so callers that must not lose them pass a `scale` at
368
+ * least `decimalScale(value)`.
369
+ */
370
+ declare const toScaled: (value: string, scale: number) => bigint;
371
+ /** Scaled integer → canonical decimal, with trailing fraction zeros trimmed. */
372
+ declare const fromScaled: (scaled: bigint, scale: number) => string;
373
+ /**
374
+ * Strip a leading `+`, leading zeros and trailing fraction zeros: `'+01.50'`
375
+ * → `'1.5'`. Requires a canonical decimal; guard with `isCanonicalDecimal`.
376
+ */
377
+ declare const normalizeDecimal: (value: string) => string;
378
+ /**
379
+ * Any numeric input → canonical decimal, expanding the exponential notation
380
+ * `String(number)` produces outside 1e-7…1e21. A `step` of `1e-7` would
381
+ * otherwise reach the arithmetic as the literal text `'1e-7'`.
382
+ *
383
+ * Throws on text that is not numeric at all — every caller here passes either
384
+ * a `number` input or text already cleared by the parser.
385
+ */
386
+ declare const toDecimal: (value: number | string) => string;
387
+ /** `-1` when `a < b`, `1` when `a > b`, `0` when equal. `'1.50'` equals `'1.5'`. */
388
+ declare const compareDecimal: (a: string, b: string) => -1 | 0 | 1;
389
+ /**
390
+ * Round to `fractionDigits`, breaking ties per `mode`. Exact where
391
+ * `Number.prototype.toFixed` is not — see the file header.
392
+ */
393
+ declare const roundDecimal: (value: string, fractionDigits: number, mode?: UniRoundingMode) => string;
394
+ /**
395
+ * Multiply by `10^places`, exactly. Used for the percent preset's
396
+ * fraction ⇄ display shift (`0.15` ⇄ `15`) and for deriving a default
397
+ * large step of `step × 10` without touching a float.
398
+ */
399
+ declare const shiftDecimal: (value: string, places: number) => string;
400
+ /**
401
+ * Hold a value inside its fences, reporting which one it hit so the caller can
402
+ * announce it. Clamping belongs on commit, never per keystroke: a `min=10`
403
+ * field that clamps live can never be typed into, because the `1` becomes `10`
404
+ * before the `5` arrives.
405
+ */
406
+ declare const clampDecimal: (value: string, min?: number | string, max?: number | string) => UniNumberClamp;
407
+ /**
408
+ * One step from `current`, in `direction` (`1` up, `-1` down).
409
+ *
410
+ * Steps land on the grid `origin + n · step`, where `origin` is `min` by
411
+ * default. A value that is *off* the grid snaps to the nearest grid point **in
412
+ * the direction of travel** rather than jumping past it: with `min=5, step=10`
413
+ * the grid is 5, 15, 25, and stepping up from 7 gives 15, not 17.
414
+ *
415
+ * Fences stop the value; they never wrap unless `wrap` is set and both bounds
416
+ * are defined. Returns `current` unchanged when `step` is zero.
417
+ */
418
+ declare const stepDecimal: (current: string, direction: 1 | -1, config?: UniNumberStepConfig) => string;
419
+
420
+ /**
421
+ * Locale separators plus, when a currency is given, its symbol, side and
422
+ * fraction digits. Memoized: constructing an `Intl.NumberFormat` is expensive
423
+ * and a field re-resolves this on every keystroke.
424
+ */
425
+ declare const localeNumberParts: (locale: string, currency?: string) => UniLocaleNumberParts;
426
+ /**
427
+ * Map localized digits and Arabic separators to ASCII, so `١٢٣٤٫٥` parses in
428
+ * `ar` and `१२३४.५` in `hi`.
429
+ */
430
+ declare const toAsciiDigits: (text: string) => string;
431
+ /**
432
+ * Evaluate `+ − × ÷ ( )` over decimal literals — shunting-yard, roughly thirty
433
+ * lines, and **never `eval`**. Returns a canonical decimal, or `null` when the
434
+ * text is not a well-formed expression.
435
+ *
436
+ * Floats are acceptable here in a way they are not elsewhere: this is a
437
+ * convenience path for spreadsheet muscle memory (`12*3`, `100/4+5`), and the
438
+ * result is settled to ten decimals before re-entering exact arithmetic.
439
+ * Division is the only operation that can produce a non-terminating decimal,
440
+ * and no exact representation would help there either.
441
+ */
442
+ declare const evaluateExpression: (text: string) => string | null;
443
+ /** Fill in every preset, locale and currency default. */
444
+ declare const resolveNumberFormat: (config?: UniNumberFormatConfig) => UniResolvedNumberFormat;
445
+ /**
446
+ * Read a user's text into a canonical decimal in **model units**.
447
+ *
448
+ * Accepted, in order: canonical/ASCII (always, whatever the locale — it is
449
+ * what agents and APIs write), locale-grouped, affixed, localized digits,
450
+ * compact (`1.5k`), accounting negatives (`(1,234.56)` → `-1234.56`), and
451
+ * expressions when `allowExpressions` is set.
452
+ */
453
+ declare const parseNumber: (raw: string, format: UniResolvedNumberFormat, options?: {
454
+ allowExpressions?: boolean;
455
+ currency?: string;
456
+ }) => UniNumberParseResult;
457
+ /**
458
+ * Canonical decimal (model units) → the display number, without affixes.
459
+ *
460
+ * `min2` grouping — the default — starts at five integer digits, so a year
461
+ * renders `2026` rather than `2,026` while a price still renders `10,000`.
462
+ */
463
+ declare const formatNumber: (canonical: string, format: UniResolvedNumberFormat) => string;
464
+ /**
465
+ * The plain text the field shows while focused: the display number with no
466
+ * grouping and no affixes, so the caret never has to walk over a separator
467
+ * that appears and vanishes mid-word.
468
+ */
469
+ declare const rawNumberText: (canonical: string, format: UniResolvedNumberFormat) => string;
470
+ /** Round a committed value to the field's precision, in model units. */
471
+ declare const settleNumber: (canonical: string, format: UniResolvedNumberFormat) => string;
472
+ /**
473
+ * The `aria-valuetext` string: the formatted number with its affixes spoken.
474
+ * `aria-valuenow` alone announces "1234.56", which is the one thing about a
475
+ * money field that is not the point. An empty field says "Empty" per APG.
476
+ */
477
+ declare const speakNumber: (canonical: string | null, format: UniResolvedNumberFormat, emptyText?: string) => string;
478
+ /** Model-units canonical decimal → the bound `number`. */
479
+ declare const toNumber: (canonical: string) => number;
480
+ /**
481
+ * True when a value cannot survive the trip through `number` — the reason the
482
+ * components also expose an exact `valueAsString` model, and the trigger for
483
+ * the dev-mode warning. Silent precision loss is the whole point of that
484
+ * second model, so it is worth saying out loud once.
485
+ *
486
+ * A `number` can only be checked for magnitude, since it has already lost
487
+ * whatever it was going to lose. A canonical string can be checked properly:
488
+ * `'9007199254740993'` comes back as `'9007199254740992'`.
489
+ */
490
+ declare const losesPrecision: (value: number | string) => boolean;
491
+
492
+ /**
493
+ * Hold-to-repeat for stepper buttons: press once to step once, hold to keep
494
+ * stepping, faster the longer you hold. Getting a quantity from 1 to 200 is
495
+ * otherwise 199 clicks.
496
+ *
497
+ * Like the other cdk helpers this owns **no DOM and attaches no listeners to
498
+ * an element** — the component's template hands it the events, which keeps the
499
+ * ARIA and the markup where they belong:
500
+ *
501
+ * ```html
502
+ * <button
503
+ * type="button"
504
+ * tabindex="-1"
505
+ * [disabled]="atMax()"
506
+ * (pointerdown)="increment.press($event)"
507
+ * (pointerup)="increment.release()"
508
+ * (pointercancel)="increment.cancel()"
509
+ * (lostpointercapture)="increment.release()"
510
+ * >
511
+ * ```
512
+ *
513
+ * It does register one `window` blur listener, because a hold that survives
514
+ * the window losing focus is a value that keeps climbing while the user is
515
+ * somewhere else. That listener is torn down with the injection context, so
516
+ * `createPressRepeat` must be called from one — a field initializer, as with
517
+ * `useTimer()`.
518
+ */
519
+
520
+ /** Repeat timings, normally sourced from a component's theme options. */
521
+ interface PressRepeatTiming {
522
+ delayMs?: number;
523
+ intervalMs?: number;
524
+ fastIntervalMs?: number;
525
+ rampMs?: number;
526
+ }
527
+ interface PressRepeatConfig {
528
+ /**
529
+ * Perform one step. `repeat` is `false` for the initial press and `true` for
530
+ * every automatic repeat, so a caller can stay silent during the run.
531
+ */
532
+ onStep: (repeat: boolean) => void;
533
+ /**
534
+ * The hold ended. `repeated` says whether it ever auto-repeated, which is
535
+ * the cue to announce the final value: a screen reader narrating two hundred
536
+ * intermediate values is a denial of service, so announcing belongs here and
537
+ * not in `onStep`.
538
+ */
539
+ onRelease?: (repeated: boolean) => void;
540
+ /** Consulted on press; a disabled button must not start a run. */
541
+ disabled?: () => boolean;
542
+ /**
543
+ * When this returns `false`, a press steps exactly once and the repeat timer
544
+ * is never armed — `onRelease` still fires, with `repeated: false`. Lets a
545
+ * caller turn hold-to-repeat off without a second set of event bindings.
546
+ */
547
+ repeat?: () => boolean;
548
+ timing?: () => PressRepeatTiming;
549
+ }
550
+ interface PressRepeat {
551
+ /** True while a press is in flight — bind it to the button's pressed state. */
552
+ readonly holding: Signal<boolean>;
553
+ /**
554
+ * Begin a hold and step once immediately. Given a pointer event, it also
555
+ * takes pointer capture, so sliding off the button mid-hold neither strands
556
+ * the repeat nor drops the release.
557
+ */
558
+ press(event?: PointerEvent): void;
559
+ /** End a hold normally, firing `onRelease`. */
560
+ release(): void;
561
+ /** End a hold without firing `onRelease` — for `Escape` and `pointercancel`. */
562
+ cancel(): void;
563
+ }
564
+ declare function createPressRepeat(config: PressRepeatConfig): PressRepeat;
565
+
190
566
  interface ListboxNavigationConfig {
191
567
  /** How many options are currently navigable. Read reactively. */
192
568
  count: () => number;
@@ -1066,7 +1442,7 @@ declare class UniDateInputComponent extends BaseComponent<UniDateInputOptions> i
1066
1442
  maxDate: _angular_core.InputSignal<string>;
1067
1443
  disabledDates: _angular_core.InputSignal<string[] | ((date: UniDate) => boolean)>;
1068
1444
  markers: _angular_core.InputSignal<UniCalendarMarker[]>;
1069
- weekStart: _angular_core.InputSignal<0 | 1 | 2 | 3 | 4 | 6 | 5>;
1445
+ weekStart: _angular_core.InputSignal<0 | 1 | 2 | 3 | 4 | 5 | 6>;
1070
1446
  /** Popup shown. */
1071
1447
  opened: _angular_core.OutputEmitterRef<void>;
1072
1448
  /** Popup hidden. */
@@ -1160,7 +1536,7 @@ declare class UniDateTimeInputComponent extends BaseComponent<UniDateTimeInputOp
1160
1536
  slots: _angular_core.InputSignal<string[]>;
1161
1537
  minuteStep: _angular_core.InputSignal<number>;
1162
1538
  hour12: _angular_core.InputSignal<boolean>;
1163
- weekStart: _angular_core.InputSignal<0 | 1 | 2 | 3 | 4 | 6 | 5>;
1539
+ weekStart: _angular_core.InputSignal<0 | 1 | 2 | 3 | 4 | 5 | 6>;
1164
1540
  locale: _angular_core.InputSignal<string>;
1165
1541
  /** Scheduling: the day's available times. Gates the time part on a date. */
1166
1542
  slotsFor: _angular_core.InputSignal<(date: UniDate) => UniTime[]>;
@@ -1230,12 +1606,26 @@ declare class UniInputBoxComponent extends BaseComponent<UniInputBoxOptions> {
1230
1606
  width: _angular_core.InputSignal<string | number>;
1231
1607
  fullWidth: _angular_core.InputSignal<boolean>;
1232
1608
  grow: _angular_core.InputSignal<number>;
1609
+ /**
1610
+ * Stop applying the themed leading inset to the inner control, for fields
1611
+ * that place it themselves.
1612
+ *
1613
+ * The inset normally rides the `<input>`, which is right while the text is
1614
+ * the field's leading edge. It is wrong the moment an adornment sits in
1615
+ * front: a currency prefix would hug the border while the number it belongs
1616
+ * to is indented past it. A field with adornments takes the inset over and
1617
+ * puts it on whichever element is actually first.
1618
+ */
1619
+ managedInset: _angular_core.InputSignal<boolean>;
1620
+ /** Auto-height fields (tag input, textarea) still keep the themed height as
1621
+ a floor, so a single-line field lines up with every other input. */
1622
+ protected readonly minHeight: _angular_core.Signal<string | number>;
1233
1623
  protected readonly color: _angular_core.Signal<_uni_design_system_uni_core.ContainerColorToken>;
1234
1624
  protected readonly border: _angular_core.Signal<string>;
1235
1625
  protected readonly shadow: _angular_core.Signal<string>;
1236
1626
  protected readonly inputBoxClass: _angular_core.Signal<string>;
1237
1627
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<UniInputBoxComponent, never>;
1238
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<UniInputBoxComponent, "uni-input-box", never, { "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "error": { "alias": "error"; "required": false; "isSignal": true; }; "minWidth": { "alias": "minWidth"; "required": false; "isSignal": true; }; "height": { "alias": "height"; "required": false; "isSignal": true; }; "width": { "alias": "width"; "required": false; "isSignal": true; }; "fullWidth": { "alias": "fullWidth"; "required": false; "isSignal": true; }; "grow": { "alias": "grow"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
1628
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UniInputBoxComponent, "uni-input-box", never, { "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "error": { "alias": "error"; "required": false; "isSignal": true; }; "minWidth": { "alias": "minWidth"; "required": false; "isSignal": true; }; "height": { "alias": "height"; "required": false; "isSignal": true; }; "width": { "alias": "width"; "required": false; "isSignal": true; }; "fullWidth": { "alias": "fullWidth"; "required": false; "isSignal": true; }; "grow": { "alias": "grow"; "required": false; "isSignal": true; }; "managedInset": { "alias": "managedInset"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
1239
1629
  }
1240
1630
 
1241
1631
  /**
@@ -1770,51 +2160,798 @@ declare class UniSelectComponent<T> implements FormValueControl<T | null> {
1770
2160
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<UniSelectComponent<any>, "uni-select", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "dirty": { "alias": "dirty"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "ariaDescribedBy": { "alias": "ariaDescribedBy"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "width": { "alias": "width"; "required": false; "isSignal": true; }; "fullWidth": { "alias": "fullWidth"; "required": false; "isSignal": true; }; "grow": { "alias": "grow"; "required": false; "isSignal": true; }; "compareWith": { "alias": "compareWith"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touched": "touchedChange"; }, never, never, true, never>;
1771
2161
  }
1772
2162
 
1773
- /** Theme-level options for `uni-slider`, resolved by token name. */
2163
+ /** A labelled stop on the track. `label` folds into `aria-valuetext` at that value. */
2164
+ interface UniSliderMark {
2165
+ value: number;
2166
+ /** Shown under the track and spoken instead of the number, e.g. `'Medium'`. */
2167
+ label?: string;
2168
+ }
2169
+ /** Which thumb a range slider is reporting on. */
2170
+ type UniSliderThumb = 'start' | 'end';
2171
+ /**
2172
+ * Theme-level options for `uni-slider`.
2173
+ *
2174
+ * Fill and thumb colour are deliberately **not** here — they are the `variant`
2175
+ * role pair, the same rule every other component follows, so `variant="warn"`
2176
+ * recolours a slider without a theme edit. The track is a groove rather than an
2177
+ * accent, so it stays a token.
2178
+ */
1774
2179
  interface UniSliderOptions {
1775
- /** Fill and thumb color. */
1776
- color?: ColorKey;
1777
- /** Unfilled track color. */
1778
- trackColor?: ColorKey;
1779
- /** Track and thumb radius token. */
1780
- borderRadius?: Radius;
1781
- /** Track height in px. */
2180
+ /** Track thickness in px. */
1782
2181
  trackHeight?: number;
1783
- /** Thumb diameter in px. */
2182
+ /** Unfilled track colour. */
2183
+ trackColor?: ContainerColorToken;
2184
+ /** Track radius token. */
2185
+ borderRadius?: Radius;
2186
+ /** Visual thumb diameter in px. The hit area is padded to `minTouchTarget`. */
1784
2187
  thumbSize?: number;
2188
+ /** Thumb radius token. */
2189
+ thumbBorderRadius?: Radius;
2190
+ /**
2191
+ * Minimum pointer target for a thumb, in px — WCAG 2.2 SC 2.5.8 floor. The
2192
+ * visual dot stays `thumbSize`; the transparent hit area grows to this.
2193
+ */
2194
+ minTouchTarget?: number;
2195
+ /** Mark dot diameter in px. */
2196
+ markSize?: number;
2197
+ /** Mark dot colour. */
2198
+ markColor?: ColorKey;
2199
+ /** Typography role for the mark labels and the inline readout. */
2200
+ labelTypeface?: Typeface;
2201
+ /** Colour of the mark labels and inline readout. */
2202
+ labelColor?: ColorKey;
2203
+ /** Tooltip background, for `valueDisplay="tooltip"`. */
2204
+ tooltipColor?: ContainerColorToken;
2205
+ /** Tooltip text colour. */
2206
+ tooltipTextColor?: ColorKey;
2207
+ tooltipShadow?: Shadow;
2208
+ tooltipBorderRadius?: Radius;
2209
+ /**
2210
+ * Click-to-jump transition in ms. A drag is never animated — a transition on
2211
+ * a dragged thumb reads as lag — so this applies to keyboard and track
2212
+ * presses only.
2213
+ */
2214
+ transitionMs?: number;
2215
+ }
2216
+
2217
+ /** Index into the thumb pair. `0` is the `start` thumb, `1` the `end` thumb. */
2218
+ type ThumbIndex = 0 | 1;
2219
+ /**
2220
+ * Bounded numeric input by pointer, for values where the *position* is the
2221
+ * information: volume, opacity, weightings, price filters.
2222
+ *
2223
+ * Custom thumbs rather than `<input type="range">`, which the previous version
2224
+ * used: one native range input cannot carry two thumbs, marks or a tooltip, and
2225
+ * a second component for the range case would mean two keyboard maps to keep in
2226
+ * step. The step model and the keyboard map are the cdk's, shared with the
2227
+ * numeric fields, so nothing new is learned moving between them.
2228
+ *
2229
+ * All arithmetic on values runs through the cdk's exact decimal helpers —
2230
+ * stepping `0.1` never yields `0.30000000000000004`. Only pointer *positions*
2231
+ * use floats, and they are snapped to the grid before becoming a value.
2232
+ */
2233
+ declare class UniSliderComponent extends BaseComponent<UniSliderOptions> implements FormValueControl<number | UniNumberRange | null> {
2234
+ /** Shape follows `mode`: a number when `single`, a `UniNumberRange` when `range`. */
2235
+ readonly value: _angular_core.ModelSignal<number | UniNumberRange>;
2236
+ readonly disabled: _angular_core.InputSignal<boolean>;
2237
+ readonly touched: _angular_core.ModelSignal<boolean>;
2238
+ readonly invalid: _angular_core.InputSignal<boolean>;
2239
+ readonly dirty: _angular_core.InputSignal<boolean>;
2240
+ readonly required: _angular_core.InputSignal<boolean>;
2241
+ readonly ariaDescribedBy: _angular_core.InputSignal<string>;
2242
+ /** Accessible name, e.g. "Opacity". Names the group in range mode. */
2243
+ label: _angular_core.InputSignal<string>;
2244
+ mode: _angular_core.InputSignal<"range" | "single">;
2245
+ min: _angular_core.InputSignal<number>;
2246
+ max: _angular_core.InputSignal<number>;
2247
+ step: _angular_core.InputSignal<number>;
2248
+ /** `PageUp`/`PageDown` and `Shift+Arrow`. Default: a tenth of the range. */
2249
+ largeStep: _angular_core.InputSignal<number>;
2250
+ /** Fill anchor. Defaults to `min`; set `0` for a slider that spans ±. */
2251
+ origin: _angular_core.InputSignal<number>;
2252
+ marks: _angular_core.InputSignal<UniSliderMark[]>;
2253
+ /** Marks become the only valid stops — t-shirt sizing, Likert scales. */
2254
+ snapToMarks: _angular_core.InputSignal<boolean>;
2255
+ /**
2256
+ * Where the current value is shown. `tooltip` appears on hover, focus and
2257
+ * drag; `inline` sits at the trailing edge of the track; `input` seats a
2258
+ * compact `uni-number-input` there, two-way bound to the same value — drag
2259
+ * for the ballpark, type for the exact figure, which is the pairing that
2260
+ * makes bounded numeric input actually usable.
2261
+ *
2262
+ * `input` applies to `single` mode only; a range would need two fields, and
2263
+ * `inline` already reads well for two ends.
2264
+ */
2265
+ valueDisplay: _angular_core.InputSignal<"input" | "none" | "tooltip" | "inline">;
2266
+ /** Overrides how a value is rendered and spoken. */
2267
+ formatValue: _angular_core.InputSignal<(value: number) => string>;
2268
+ /** Enforced distance between the two ends, in range mode. */
2269
+ minGap: _angular_core.InputSignal<number>;
2270
+ variant: _angular_core.InputSignal<Variant>;
2271
+ /** Continuous, during a drag or a held key. Bind this for a live preview. */
2272
+ sliding: _angular_core.OutputEmitterRef<number | UniNumberRange>;
2273
+ /**
2274
+ * Committed — on pointer release and key-up. **A form should bind this**:
2275
+ * piping a 60 Hz stream into a model is how sliders get blamed for jank.
2276
+ */
2277
+ changed: _angular_core.OutputEmitterRef<number | UniNumberRange>;
2278
+ private readonly trackRef;
2279
+ private readonly thumbRefs;
2280
+ protected readonly srOnly: string;
2281
+ /** Fences and swaps only — `aria-valuetext` already narrates movement. */
2282
+ protected readonly announcer: _uni_design_system_uni_angular.Announcer;
2283
+ protected readonly groupId: string;
2284
+ /** True from pointerdown until release, to suppress the jump transition. */
2285
+ protected readonly dragging: _angular_core.WritableSignal<boolean>;
2286
+ private draggingThumb;
2287
+ /** Set by keydown, consumed by keyup, so one commit follows a key run. */
2288
+ private keyed;
2289
+ protected readonly isRange: _angular_core.Signal<boolean>;
2290
+ protected readonly resolvedMin: _angular_core.Signal<number>;
2291
+ protected readonly resolvedMax: _angular_core.Signal<number>;
2292
+ private derivePair;
2293
+ /**
2294
+ * The two thumb positions, by **identity** rather than by order: thumb 0 is
2295
+ * whichever thumb the user grabbed first, not necessarily the lower one.
2296
+ *
2297
+ * A `linkedSignal` so an external write to `value` resets them, while a drag
2298
+ * moves them without writing the model on every frame. The computation
2299
+ * deliberately keeps the existing order when the incoming value describes the
2300
+ * same two positions — a commit writes the range back *sorted*, and
2301
+ * re-deriving from that would un-cross a crossed pair and yank the dragged
2302
+ * thumb out from under the pointer mid-drag.
2303
+ */
2304
+ private readonly thumbs;
2305
+ protected readonly thumbIndexes: _angular_core.Signal<ThumbIndex[]>;
2306
+ protected readonly showError: _angular_core.Signal<boolean>;
2307
+ /** Default large step: a tenth of the range, snapped to the step grid. */
2308
+ private readonly resolvedLargeStep;
2309
+ private readonly numberFormat;
2310
+ protected formatted(value: number): string;
2311
+ /** A mark's label speaks for its value, so a marks-only slider says "Medium". */
2312
+ private markLabel;
2313
+ protected valueText(value: number): string;
2314
+ protected percentOf(value: number): number;
2315
+ protected readonly lowValue: _angular_core.Signal<number>;
2316
+ protected readonly highValue: _angular_core.Signal<number>;
2317
+ /** The fill spans between the ends in range mode, or origin → value. */
2318
+ protected readonly fillStart: _angular_core.Signal<number>;
2319
+ protected readonly fillEnd: _angular_core.Signal<number>;
2320
+ protected readonly hasMarkLabels: _angular_core.Signal<boolean>;
2321
+ /** The number-field readout only makes sense for a single value. */
2322
+ protected readonly showReadoutField: _angular_core.Signal<boolean>;
2323
+ /** Fraction digits the readout should accept, taken from the step. */
2324
+ protected readonly readoutDecimals: _angular_core.Signal<[number, number]>;
2325
+ /**
2326
+ * The readout drives the thumb. Guarded against the write-back cycle: the
2327
+ * field is fed from `value`, so a commit here would otherwise bounce.
2328
+ */
2329
+ protected onReadoutValue(next: number | null): void;
2330
+ protected thumbValue(index: ThumbIndex): number;
2331
+ /**
2332
+ * Each thumb's bound is the *other thumb's* position, so a screen-reader user
2333
+ * is told where the wall actually is rather than where the track ends.
2334
+ */
2335
+ protected thumbMin(index: ThumbIndex): number;
2336
+ protected thumbMax(index: ThumbIndex): number;
2337
+ /** Thumbs may cross; which one is "minimum" follows position, not identity. */
2338
+ private isLower;
2339
+ protected thumbLabel(index: ThumbIndex): string;
2340
+ private currentValue;
2341
+ /** Exact `min + n · step`, so a snapped position never carries float drift. */
2342
+ private snapToGrid;
2343
+ private clamp;
2344
+ /**
2345
+ * Move a thumb. `commit` writes the model and emits `changed`; without it the
2346
+ * move is visual and only emits `sliding`.
2347
+ */
2348
+ private setThumb;
2349
+ private commit;
2350
+ private announceValue;
2351
+ /** True when the track is laid out right-to-left. */
2352
+ private isRtl;
2353
+ /** Pointer x → a raw value. The track's visual direction flips in RTL; the value's does not. */
2354
+ private valueFromPointer;
2355
+ private nearestThumb;
2356
+ protected onTrackPointerDown(event: PointerEvent): void;
2357
+ protected onTrackPointerMove(event: PointerEvent): void;
2358
+ protected onTrackPointerUp(): void;
2359
+ /** Adjacent mark, when marks are the only stops. */
2360
+ private markStep;
2361
+ private stepFrom;
2362
+ protected onThumbKeydown(event: KeyboardEvent, index: ThumbIndex): void;
2363
+ /** One commit and one announcement per key run, not per repeat. */
2364
+ protected onThumbKeyup(index: ThumbIndex): void;
2365
+ protected onThumbBlur(): void;
2366
+ protected readonly className: _angular_core.Signal<string>;
2367
+ private readonly fillColor;
2368
+ protected readonly rootClass: _angular_core.Signal<string>;
2369
+ protected readonly rowClass: _angular_core.Signal<string>;
2370
+ protected readonly trackClass: _angular_core.Signal<string>;
2371
+ protected readonly fillClass: _angular_core.Signal<string>;
2372
+ protected readonly markClass: _angular_core.Signal<string>;
2373
+ protected readonly thumbClass: _angular_core.Signal<string>;
2374
+ protected readonly tooltipClass: _angular_core.Signal<string>;
2375
+ protected readonly labelsClass: _angular_core.Signal<string>;
2376
+ protected readonly labelClass: _angular_core.Signal<string>;
2377
+ /** Narrow enough that the track keeps most of the row. */
2378
+ protected readonly readoutFieldClass: _angular_core.Signal<string>;
2379
+ protected readonly readoutClass: _angular_core.Signal<string>;
2380
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UniSliderComponent, never>;
2381
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UniSliderComponent, "uni-slider, Slider", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "dirty": { "alias": "dirty"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "ariaDescribedBy": { "alias": "ariaDescribedBy"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": true; "isSignal": true; }; "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "step": { "alias": "step"; "required": false; "isSignal": true; }; "largeStep": { "alias": "largeStep"; "required": false; "isSignal": true; }; "origin": { "alias": "origin"; "required": false; "isSignal": true; }; "marks": { "alias": "marks"; "required": false; "isSignal": true; }; "snapToMarks": { "alias": "snapToMarks"; "required": false; "isSignal": true; }; "valueDisplay": { "alias": "valueDisplay"; "required": false; "isSignal": true; }; "formatValue": { "alias": "formatValue"; "required": false; "isSignal": true; }; "minGap": { "alias": "minGap"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touched": "touchedChange"; "sliding": "sliding"; "changed": "changed"; }, never, never, true, never>;
2382
+ }
2383
+
2384
+ /**
2385
+ * Where the stepper buttons sit.
2386
+ *
2387
+ * `stacked` is the dense desktop default; `split` (− … +) is the touch and
2388
+ * quantity language; `trailing` puts − and + together at the end; `none` hides
2389
+ * them, leaving the arrow keys as the only step route.
2390
+ */
2391
+ type UniStepperLayout = 'stacked' | 'split' | 'trailing' | 'none';
2392
+ /** A refused commit. The raw text stays in the field rather than being dropped. */
2393
+ interface UniNumberRejection {
2394
+ raw: string;
2395
+ reason: UniNumberRejectReason;
2396
+ }
2397
+ /** A committed step, for callers that need to distinguish it from typing. */
2398
+ interface UniNumberStepped {
2399
+ from: number | null;
2400
+ to: number;
2401
+ /** The signed amount applied, e.g. `-10` for a large step down. */
2402
+ by: number;
2403
+ }
2404
+ /**
2405
+ * Theme-level options for `uni-number-input`.
2406
+ *
2407
+ * Field chrome — colour, border, radius, focus outline — is **not** duplicated
2408
+ * here. It comes from the shared `input` options via `uni-input-box`, exactly
2409
+ * like tag-input, date-input and combobox, so a number field restyles with
2410
+ * every other field.
2411
+ */
2412
+ interface UniNumberInputOptions {
2413
+ stepperLayout?: UniStepperLayout;
2414
+ /** Glyph for the `+` button in the split and trailing layouts. */
2415
+ incrementIcon?: IconName;
2416
+ /** Glyph for the `−` button in the split and trailing layouts. */
2417
+ decrementIcon?: IconName;
2418
+ /** Glyph for the upper arrow in the stacked layout. */
2419
+ stepUpIcon?: IconName;
2420
+ /** Glyph for the lower arrow in the stacked layout. */
2421
+ stepDownIcon?: IconName;
2422
+ /** Width of a stepper column in px. */
2423
+ stepperWidth?: number;
2424
+ /**
2425
+ * Minimum pointer target for a stepper button, in px — WCAG 2.2 SC 2.5.8.
2426
+ * Applies to the `split` and `trailing` layouts; the two `stacked` arrows
2427
+ * share the field height instead, which is why a coarse pointer switches to
2428
+ * `split`.
2429
+ */
2430
+ minTouchTarget?: number;
2431
+ /** Colour of the prefix/suffix adornments. */
2432
+ affixColor?: ColorKey;
2433
+ /** Space between an adornment and the editable text. */
2434
+ affixGap?: NullableSize;
2435
+ /** Default text alignment; the `align` input overrides it per instance. */
2436
+ align?: 'start' | 'end' | 'center';
2437
+ /** `font-variant-numeric: tabular-nums`, so held stepping does not jitter. */
2438
+ tabularNumerals?: boolean;
2439
+ /** Hold this long before the stepper starts repeating. */
2440
+ repeatDelayMs?: number;
2441
+ /** Repeat period once it starts. */
2442
+ repeatIntervalMs?: number;
2443
+ /** Repeat period at full speed. */
2444
+ repeatFastIntervalMs?: number;
2445
+ /** Hold this long before the repeat begins accelerating. */
2446
+ repeatRampMs?: number;
1785
2447
  }
1786
2448
 
1787
2449
  /**
1788
- * Range slider on a native `<input type="range">` keyboard interaction and
1789
- * the ARIA slider contract come from the platform. Fill, track, thumb and
1790
- * radii resolve from `slider` theme tokens; the fill percentage rides a CSS
1791
- * custom property so dragging never regenerates styles.
2450
+ * Numeric field with locale-aware parsing, `Intl` formatting on commit,
2451
+ * prefix/suffix adornments and steppers that hold to repeat.
2452
+ *
2453
+ * Not `<input type="number">`, and the first reason is a data-loss bug: per the
2454
+ * HTML value sanitization algorithm, a number input whose text is not a valid
2455
+ * floating-point number reports `value === ''`. Type `12,50` as most of Europe
2456
+ * does, or paste `1,234.56` from a spreadsheet, and the app reads an empty
2457
+ * field. This is `type="text"` with `role="spinbutton"`, which is the only way
2458
+ * to keep the user's malformed text on screen and tell them about it.
2459
+ *
2460
+ * Chrome comes from `uni-input-box`, so error, disabled and focus states match
2461
+ * every other field. All arithmetic runs on the cdk's exact decimal helpers.
1792
2462
  */
1793
- declare class UniSliderComponent extends BaseComponent<UniSliderOptions> implements FormValueControl<number> {
2463
+ declare class UniNumberInputComponent extends BaseComponent<UniNumberInputOptions> implements FormValueControl<number | null> {
1794
2464
  readonly value: _angular_core.ModelSignal<number>;
1795
2465
  readonly disabled: _angular_core.InputSignal<boolean>;
1796
2466
  readonly touched: _angular_core.ModelSignal<boolean>;
1797
2467
  readonly invalid: _angular_core.InputSignal<boolean>;
1798
2468
  readonly dirty: _angular_core.InputSignal<boolean>;
1799
- /** Synced from required() validators by the Signal Forms [field] directive. */
1800
2469
  readonly required: _angular_core.InputSignal<boolean>;
2470
+ readonly ariaDescribedBy: _angular_core.InputSignal<string>;
1801
2471
  /**
1802
- * Id(s) of external element(s) describing this control typically your
1803
- * app-rendered value or error text exposed as aria-describedby.
2472
+ * Exact binding, as a canonical decimal string. Bind this instead of `value`
2473
+ * where a cent in the fifth decimal place matters; both stay in sync, so it
2474
+ * is a one-word change from the ordinary case.
2475
+ */
2476
+ readonly valueAsString: _angular_core.ModelSignal<string>;
2477
+ /** Accessible name, e.g. "Unit price". */
2478
+ label: _angular_core.InputSignal<string>;
2479
+ placeholder: _angular_core.InputSignal<string>;
2480
+ preset: _angular_core.InputSignal<UniNumberPreset>;
2481
+ /** ISO 4217 code, e.g. `'USD'`. Implies `preset="currency"`. */
2482
+ currency: _angular_core.InputSignal<string>;
2483
+ /** BCP 47 tag. Defaults to the document language, then the browser's. */
2484
+ locale: _angular_core.InputSignal<string>;
2485
+ /** Static adornment before the number, e.g. `'$'`. Never parseable input. */
2486
+ prefix: _angular_core.InputSignal<string>;
2487
+ /** Static adornment after the number, e.g. `'kg'`, `'/mo'`. */
2488
+ suffix: _angular_core.InputSignal<string>;
2489
+ decimals: _angular_core.InputSignal<number | [min: number, max: number]>;
2490
+ grouping: _angular_core.InputSignal<false | "auto" | "always" | "min2">;
2491
+ /** Escape hatch, merged over the preset. */
2492
+ numberFormat: _angular_core.InputSignal<Intl.NumberFormatOptions>;
2493
+ roundingMode: _angular_core.InputSignal<UniRoundingMode>;
2494
+ align: _angular_core.InputSignal<"center" | "start" | "end">;
2495
+ /** The model is a fraction: `0.15` displays as `15%`. */
2496
+ valueIsFraction: _angular_core.InputSignal<boolean>;
2497
+ /** Spoken long form of an abbreviated suffix, e.g. `'kilograms'` for `kg`. */
2498
+ unitAnnouncement: _angular_core.InputSignal<string>;
2499
+ readOnly: _angular_core.InputSignal<boolean>;
2500
+ /** Renders without its own input-box chrome, for composers like uni-slider. */
2501
+ embedded: _angular_core.InputSignal<boolean>;
2502
+ min: _angular_core.InputSignal<number>;
2503
+ max: _angular_core.InputSignal<number>;
2504
+ step: _angular_core.InputSignal<number>;
2505
+ /** `PageUp`/`PageDown` and `Shift+Arrow`. Default: `step × 10`. */
2506
+ largeStep: _angular_core.InputSignal<number>;
2507
+ /** `Alt+Arrow`, Figma's fine-nudge convention. Unset disables it. */
2508
+ smallStep: _angular_core.InputSignal<number>;
2509
+ stepOrigin: _angular_core.InputSignal<"min" | "zero">;
2510
+ /** Cyclic fields only — 23 → 0 hours, 359 → 0 degrees. */
2511
+ wrap: _angular_core.InputSignal<boolean>;
2512
+ /** `false` refuses an out-of-range commit instead of clamping it. */
2513
+ clampOnCommit: _angular_core.InputSignal<boolean>;
2514
+ /** What ↑ commits on an empty field. Default: `min ?? 0`. */
2515
+ emptyStepValue: _angular_core.InputSignal<number>;
2516
+ commitOnBlur: _angular_core.InputSignal<boolean>;
2517
+ selectOnFocus: _angular_core.InputSignal<boolean>;
2518
+ /** `12*3` → 36. Off by default: a parser in a form field is a real cost. */
2519
+ allowExpressions: _angular_core.InputSignal<boolean>;
2520
+ /** Scroll-to-step. Off by default — see `onWheel`. */
2521
+ wheel: _angular_core.InputSignal<boolean>;
2522
+ repeat: _angular_core.InputSignal<boolean>;
2523
+ /** Custom parser, replacing the built-in locale parsing. */
2524
+ parse: _angular_core.InputSignal<(raw: string, locale: string) => string | null>;
2525
+ /** Overrides the themed layout for this instance. */
2526
+ stepperLayout: _angular_core.InputSignal<_uni_design_system_uni_angular.UniStepperLayout>;
2527
+ stepped: _angular_core.OutputEmitterRef<UniNumberStepped>;
2528
+ /** A commit was refused; the raw text stays in the field. */
2529
+ rejected: _angular_core.OutputEmitterRef<UniNumberRejection>;
2530
+ private readonly inputRef;
2531
+ protected readonly srOnly: string;
2532
+ /** Clamps, fences, rejections and expression results are otherwise silent. */
2533
+ protected readonly announcer: _uni_design_system_uni_angular.Announcer;
2534
+ protected readonly hintId: string;
2535
+ /** Uncommitted text. `null` means "show the committed value". */
2536
+ private readonly draft;
2537
+ /** A commit that failed — styles the field until the text is edited. */
2538
+ protected readonly draftInvalid: _angular_core.WritableSignal<boolean>;
2539
+ protected readonly focused: _angular_core.WritableSignal<boolean>;
2540
+ /**
2541
+ * The canonical decimal behind both models — the field's source of truth.
2542
+ *
2543
+ * Two models that each accept writes need a rule for which one won, and
2544
+ * "whichever the app touched last" is the only one that does not surprise
2545
+ * somebody. A `linkedSignal` over both gives us that: the model whose value
2546
+ * differs from the previous source is the one that changed.
2547
+ *
2548
+ * The subtlety is the echo. Committing writes both models, and the `value`
2549
+ * projection of a 17-digit exact string is lossy — so on the next pass
2550
+ * `value` looks changed, and naively adopting it would clobber the very
2551
+ * precision `valueAsString` exists to keep. A changed `value` that already
2552
+ * matches `Number(exact)` is our own projection coming back, not a write.
2553
+ */
2554
+ private readonly canonical;
2555
+ constructor();
2556
+ protected readonly resolvedLocale: _angular_core.Signal<string>;
2557
+ protected readonly format: _angular_core.Signal<_uni_design_system_uni_angular.UniResolvedNumberFormat>;
2558
+ /**
2559
+ * Two stacked arrows cannot both be 24px tall inside a 32px field, so on a
2560
+ * coarse pointer the stacked layout becomes `split`, where each button is a
2561
+ * full-height square and clears the WCAG 2.2 SC 2.5.8 floor. Two 12px
2562
+ * targets under a fingertip is a coin toss.
2563
+ */
2564
+ private readonly coarsePointer;
2565
+ protected readonly layout: _angular_core.Signal<_uni_design_system_uni_angular.UniStepperLayout>;
2566
+ protected readonly showSteppers: _angular_core.Signal<boolean>;
2567
+ protected readonly showError: _angular_core.Signal<boolean>;
2568
+ /** Raw while focused, formatted once committed — no caret arithmetic ever. */
2569
+ protected readonly displayText: _angular_core.Signal<string>;
2570
+ protected readonly valueTextForAria: _angular_core.Signal<string>;
2571
+ /**
2572
+ * `aria-valuenow` is omitted entirely on an empty field, per APG — a
2573
+ * spinbutton reporting 0 for "nothing yet" is a wrong answer, not a missing
2574
+ * one. `aria-valuetext` carries the localized "Empty" instead.
2575
+ */
2576
+ protected readonly canonicalForAria: _angular_core.Signal<string>;
2577
+ protected readonly describedBy: _angular_core.Signal<string>;
2578
+ private atFence;
2579
+ protected readonly atMin: _angular_core.Signal<boolean>;
2580
+ protected readonly atMax: _angular_core.Signal<boolean>;
2581
+ /** Set the source of truth; the constructor's effect pushes it to both models. */
2582
+ private write;
2583
+ /**
2584
+ * Turn the draft into a value. Out-of-range either clamps (announced) or is
2585
+ * refused, per `clampOnCommit`; unreadable text stays in the field, flagged.
2586
+ */
2587
+ protected commitDraft(): void;
2588
+ private acceptValue;
2589
+ private reject;
2590
+ private rejectionMessage;
2591
+ private stepSize;
2592
+ /**
2593
+ * Apply one step. An empty field commits `emptyStepValue ?? min ?? 0`, so ↑
2594
+ * on a blank quantity gives 1 rather than NaN.
2595
+ */
2596
+ protected applyStep(direction: 1 | -1, magnitude?: 'small' | 'normal' | 'large', announce?: boolean): void;
2597
+ private announceValue;
2598
+ private announceFence;
2599
+ private readonly repeatTiming;
2600
+ /**
2601
+ * The live region announces on release only — a screen reader narrating two
2602
+ * hundred intermediate values is a denial of service.
2603
+ */
2604
+ protected readonly increment: _uni_design_system_uni_angular.PressRepeat;
2605
+ protected readonly decrement: _uni_design_system_uni_angular.PressRepeat;
2606
+ protected onInput(text: string): void;
2607
+ protected onFocus(): void;
2608
+ protected onBlur(): void;
2609
+ protected onKeydown(event: KeyboardEvent): void;
2610
+ /**
2611
+ * Scroll-to-step, off by default. A *focused* `<input type="number">` changes
2612
+ * value on the wheel, which silently corrupts forms people are merely
2613
+ * scrolling past. When enabled this needs focus **and** hover, and it only
2614
+ * calls `preventDefault` when the value actually moved, so a page does not
2615
+ * get scroll-trapped on a field sitting at its max.
1804
2616
  */
2617
+ protected onWheel(event: WheelEvent): void;
2618
+ protected readonly className: _angular_core.Signal<string>;
2619
+ protected readonly fieldRowClass: _angular_core.Signal<string>;
2620
+ /** The shared field inset, reused on the trailing side so the two match. */
2621
+ private readonly trailingInset;
2622
+ protected readonly inputClass: _angular_core.Signal<string>;
2623
+ /**
2624
+ * The shared field chrome, read from the `input` theme entry — the same entry
2625
+ * `uni-input-box` resolves. Not a duplicate token: the inset has to be the
2626
+ * one every other field uses, or a money field stops lining up with the text
2627
+ * field above it.
2628
+ */
2629
+ private readonly fieldChrome;
2630
+ /**
2631
+ * The leading inset for a prefix adornment. When there is a prefix the field
2632
+ * tells the box to stop insetting the `<input>` (`managedInset`) and puts the
2633
+ * inset here instead, so the `$` sits at the field's leading edge with the
2634
+ * number right after it. With no prefix the box keeps doing it — the text is
2635
+ * the leading edge then, and the box's rule outranks this class anyway.
2636
+ * `embedded` fields have no chrome, so they get no inset either.
2637
+ */
2638
+ private readonly leadingInset;
2639
+ private affixBase;
2640
+ /** Carries the field's leading inset, being the first thing in the row. */
2641
+ protected readonly prefixClass: _angular_core.Signal<string>;
2642
+ protected readonly suffixClass: _angular_core.Signal<string>;
2643
+ /** Shared chrome for every stepper button, in any layout. */
2644
+ private stepperButton;
2645
+ /** Split and trailing layouts: one square button per direction. */
2646
+ protected readonly stepperClass: _angular_core.Signal<string>;
2647
+ /** Stacked layout: two half-height arrows sharing one column. */
2648
+ protected readonly stackedColumnClass: _angular_core.Signal<string>;
2649
+ protected readonly stackedButtonClass: _angular_core.Signal<string>;
2650
+ protected readonly glyphSize: _angular_core.Signal<12 | 18>;
2651
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UniNumberInputComponent, never>;
2652
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UniNumberInputComponent, "uni-number-input, NumberInput", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "dirty": { "alias": "dirty"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "ariaDescribedBy": { "alias": "ariaDescribedBy"; "required": false; "isSignal": true; }; "valueAsString": { "alias": "valueAsString"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": true; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "preset": { "alias": "preset"; "required": false; "isSignal": true; }; "currency": { "alias": "currency"; "required": false; "isSignal": true; }; "locale": { "alias": "locale"; "required": false; "isSignal": true; }; "prefix": { "alias": "prefix"; "required": false; "isSignal": true; }; "suffix": { "alias": "suffix"; "required": false; "isSignal": true; }; "decimals": { "alias": "decimals"; "required": false; "isSignal": true; }; "grouping": { "alias": "grouping"; "required": false; "isSignal": true; }; "numberFormat": { "alias": "numberFormat"; "required": false; "isSignal": true; }; "roundingMode": { "alias": "roundingMode"; "required": false; "isSignal": true; }; "align": { "alias": "align"; "required": false; "isSignal": true; }; "valueIsFraction": { "alias": "valueIsFraction"; "required": false; "isSignal": true; }; "unitAnnouncement": { "alias": "unitAnnouncement"; "required": false; "isSignal": true; }; "readOnly": { "alias": "readOnly"; "required": false; "isSignal": true; }; "embedded": { "alias": "embedded"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "step": { "alias": "step"; "required": false; "isSignal": true; }; "largeStep": { "alias": "largeStep"; "required": false; "isSignal": true; }; "smallStep": { "alias": "smallStep"; "required": false; "isSignal": true; }; "stepOrigin": { "alias": "stepOrigin"; "required": false; "isSignal": true; }; "wrap": { "alias": "wrap"; "required": false; "isSignal": true; }; "clampOnCommit": { "alias": "clampOnCommit"; "required": false; "isSignal": true; }; "emptyStepValue": { "alias": "emptyStepValue"; "required": false; "isSignal": true; }; "commitOnBlur": { "alias": "commitOnBlur"; "required": false; "isSignal": true; }; "selectOnFocus": { "alias": "selectOnFocus"; "required": false; "isSignal": true; }; "allowExpressions": { "alias": "allowExpressions"; "required": false; "isSignal": true; }; "wheel": { "alias": "wheel"; "required": false; "isSignal": true; }; "repeat": { "alias": "repeat"; "required": false; "isSignal": true; }; "parse": { "alias": "parse"; "required": false; "isSignal": true; }; "stepperLayout": { "alias": "stepperLayout"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touched": "touchedChange"; "valueAsString": "valueAsStringChange"; "stepped": "stepped"; "rejected": "rejected"; }, never, never, true, never>;
2653
+ }
2654
+
2655
+ /** Which end of the range a rejection or a change came from. */
2656
+ type UniNumberRangePart = 'start' | 'end';
2657
+ /** A refused commit on one end. The raw text stays in that part. */
2658
+ interface UniNumberRangeRejection {
2659
+ part: UniNumberRangePart;
2660
+ raw: string;
2661
+ reason: 'unparseable' | 'not-integer';
2662
+ }
2663
+ /**
2664
+ * Theme-level options for `uni-number-range-input`.
2665
+ *
2666
+ * Field chrome — colour, border, radius, focus outline — is not duplicated
2667
+ * here; it comes from the shared `input` options via `uni-input-box`, so a
2668
+ * range field restyles with every other field. These are the composer's own.
2669
+ */
2670
+ interface UniNumberRangeInputOptions {
2671
+ /** Space between each part and the divider. */
2672
+ partGap?: NullableSize;
2673
+ /**
2674
+ * Text between the two ends. Literal punctuation, not an icon token — an en
2675
+ * dash between two numbers is not a glyph a theme swaps artwork for.
2676
+ */
2677
+ dividerText?: string;
2678
+ dividerColor?: ColorKey;
2679
+ /** Colour of each part's prefix/suffix adornment. */
2680
+ affixColor?: ColorKey;
2681
+ /** Space between an adornment and its number. */
2682
+ affixGap?: NullableSize;
2683
+ }
2684
+
2685
+ /**
2686
+ * Two linked numeric fields in one chrome, with one `{ start, end }` value —
2687
+ * price filters, thresholds, tolerances.
2688
+ *
2689
+ * `start`/`end` deliberately match `UniDateRange`, so the library has one range
2690
+ * vocabulary, and they avoid colliding with the `min`/`max` **inputs**, which
2691
+ * mean the fence rather than the value.
2692
+ *
2693
+ * It owns its commit path rather than nesting two `uni-number-input`s, because
2694
+ * the two behaviours the spec asks for need *different* bounds: a stepper must
2695
+ * be fenced at the other end, while a typed commit must reach the parent
2696
+ * un-clamped so a backwards range can be swapped instead of destroyed. A child
2697
+ * field applies one bound pair to both. The arithmetic, parsing and formatting
2698
+ * are still the cdk's, shared with every other numeric control.
2699
+ */
2700
+ declare class UniNumberRangeInputComponent extends BaseComponent<UniNumberRangeInputOptions> implements FormValueControl<UniNumberRange | null> {
2701
+ readonly value: _angular_core.ModelSignal<UniNumberRange>;
2702
+ readonly disabled: _angular_core.InputSignal<boolean>;
2703
+ readonly touched: _angular_core.ModelSignal<boolean>;
2704
+ readonly invalid: _angular_core.InputSignal<boolean>;
2705
+ readonly dirty: _angular_core.InputSignal<boolean>;
2706
+ readonly required: _angular_core.InputSignal<boolean>;
1805
2707
  readonly ariaDescribedBy: _angular_core.InputSignal<string>;
2708
+ /** Names the group, e.g. "Price range". */
1806
2709
  label: _angular_core.InputSignal<string>;
2710
+ startLabel: _angular_core.InputSignal<string>;
2711
+ endLabel: _angular_core.InputSignal<string>;
2712
+ preset: _angular_core.InputSignal<UniNumberPreset>;
2713
+ currency: _angular_core.InputSignal<string>;
2714
+ locale: _angular_core.InputSignal<string>;
2715
+ prefix: _angular_core.InputSignal<string>;
2716
+ suffix: _angular_core.InputSignal<string>;
2717
+ decimals: _angular_core.InputSignal<number | [min: number, max: number]>;
2718
+ grouping: _angular_core.InputSignal<false | "auto" | "always" | "min2">;
2719
+ roundingMode: _angular_core.InputSignal<UniRoundingMode>;
2720
+ placeholderStart: _angular_core.InputSignal<string>;
2721
+ placeholderEnd: _angular_core.InputSignal<string>;
1807
2722
  min: _angular_core.InputSignal<number>;
1808
2723
  max: _angular_core.InputSignal<number>;
1809
2724
  step: _angular_core.InputSignal<number>;
2725
+ /** Enforced distance between the two ends. */
2726
+ minGap: _angular_core.InputSignal<number>;
2727
+ /** The ends were entered backwards and have been exchanged. */
2728
+ swapped: _angular_core.OutputEmitterRef<UniNumberRange>;
2729
+ /** A typed commit on one end could not be read; its text stays in place. */
2730
+ rejected: _angular_core.OutputEmitterRef<UniNumberRangeRejection>;
2731
+ private readonly inputRefs;
2732
+ protected readonly srOnly: string;
2733
+ protected readonly announcer: _uni_design_system_uni_angular.Announcer;
2734
+ protected readonly hintId: string;
2735
+ protected readonly groupId: string;
2736
+ /** Uncommitted text per part. `null` means "show the committed value". */
2737
+ private readonly drafts;
2738
+ private readonly focusedPart;
2739
+ private readonly invalidPart;
2740
+ protected readonly parts: readonly UniNumberRangePart[];
2741
+ private readonly fieldChrome;
2742
+ protected readonly format: _angular_core.Signal<_uni_design_system_uni_angular.UniResolvedNumberFormat>;
2743
+ /** Form-level error, which belongs to both ends. */
2744
+ protected readonly formError: _angular_core.Signal<boolean>;
2745
+ /**
2746
+ * Box-level error. A refused draft in *one* end flags the shared chrome, but
2747
+ * must not flag the other end's input — that end is fine.
2748
+ */
2749
+ protected readonly showError: _angular_core.Signal<boolean>;
2750
+ protected readonly describedBy: _angular_core.Signal<string>;
2751
+ /** The committed canonical decimal for a part, or `null` when that end is open. */
2752
+ private canonicalOf;
2753
+ protected valueOf(part: UniNumberRangePart): number | null;
2754
+ protected displayText(part: UniNumberRangePart): string;
2755
+ protected partLabel(part: UniNumberRangePart): string;
2756
+ protected valueTextOf(part: UniNumberRangePart): string;
2757
+ protected isInvalid(part: UniNumberRangePart): boolean;
2758
+ /** Exact `a ± b` without a float, for the gap arithmetic. */
2759
+ private shiftBy;
2760
+ /**
2761
+ * The fence a part's **stepping** and its ARIA see: the other end, held off
2762
+ * by `minGap`, intersected with the outer bounds. This is deliberately
2763
+ * tighter than what a typed commit is measured against — the steppers must
2764
+ * not walk one end through the other, while typing a backwards range should
2765
+ * be swapped rather than clamped away.
2766
+ */
2767
+ protected stepFence(part: UniNumberRangePart): {
2768
+ min?: number;
2769
+ max?: number;
2770
+ };
2771
+ private writeRange;
2772
+ protected onInput(part: UniNumberRangePart, text: string): void;
2773
+ /**
2774
+ * Commit one part. Out-of-range clamps to the **outer** bounds only, so the
2775
+ * other end never destroys what was typed; the ends are then reconciled.
2776
+ */
2777
+ protected commitPart(part: UniNumberRangePart): void;
2778
+ /**
2779
+ * Put the two ends in order. A backwards pair is **swapped**, not refused —
2780
+ * the same rule `uni-calendar` applies to a backwards date range, because the
2781
+ * user pointed at the range they meant. Otherwise `minGap` is honoured by
2782
+ * pushing the end that was just edited back to the boundary, which is what
2783
+ * makes stepping behave as a fence rather than dragging the other end along.
2784
+ */
2785
+ private reconcile;
2786
+ protected applyStep(part: UniNumberRangePart, direction: 1 | -1, large?: boolean): void;
2787
+ private announceValue;
2788
+ protected onFocus(part: UniNumberRangePart): void;
2789
+ protected onBlur(part: UniNumberRangePart): void;
2790
+ protected onKeydown(event: KeyboardEvent, part: UniNumberRangePart): void;
2791
+ protected readonly className: _angular_core.Signal<string>;
2792
+ protected readonly rowClass: _angular_core.Signal<string>;
2793
+ /** Each end is its own `[prefix][number][suffix]` group. */
2794
+ protected readonly partWrapClass: _angular_core.Signal<string>;
2795
+ protected readonly affixClass: _angular_core.Signal<string>;
2796
+ protected readonly partClass: _angular_core.Signal<string>;
2797
+ private partBase;
2798
+ protected readonly invalidClass: _angular_core.Signal<string>;
2799
+ protected readonly dividerClass: _angular_core.Signal<string>;
2800
+ protected readonly dividerText: _angular_core.Signal<string>;
2801
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UniNumberRangeInputComponent, never>;
2802
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UniNumberRangeInputComponent, "uni-number-range-input, NumberRangeInput", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "dirty": { "alias": "dirty"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "ariaDescribedBy": { "alias": "ariaDescribedBy"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": true; "isSignal": true; }; "startLabel": { "alias": "startLabel"; "required": false; "isSignal": true; }; "endLabel": { "alias": "endLabel"; "required": false; "isSignal": true; }; "preset": { "alias": "preset"; "required": false; "isSignal": true; }; "currency": { "alias": "currency"; "required": false; "isSignal": true; }; "locale": { "alias": "locale"; "required": false; "isSignal": true; }; "prefix": { "alias": "prefix"; "required": false; "isSignal": true; }; "suffix": { "alias": "suffix"; "required": false; "isSignal": true; }; "decimals": { "alias": "decimals"; "required": false; "isSignal": true; }; "grouping": { "alias": "grouping"; "required": false; "isSignal": true; }; "roundingMode": { "alias": "roundingMode"; "required": false; "isSignal": true; }; "placeholderStart": { "alias": "placeholderStart"; "required": false; "isSignal": true; }; "placeholderEnd": { "alias": "placeholderEnd"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "step": { "alias": "step"; "required": false; "isSignal": true; }; "minGap": { "alias": "minGap"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touched": "touchedChange"; "swapped": "swapped"; "rejected": "rejected"; }, never, never, true, never>;
2803
+ }
2804
+
2805
+ /**
2806
+ * Theme-level options for `uni-quantity-stepper`.
2807
+ *
2808
+ * Unlike the other numeric controls this does **not** inherit the shared
2809
+ * `input` chrome — it is not a field, has no label and no error border — so it
2810
+ * carries its own container tokens. They default to the same values `input`
2811
+ * uses, so a cart stepper and a form field look related out of the box, and a
2812
+ * theme can part them without editing every field.
2813
+ *
2814
+ * Height comes from the `sizes` block (`sm` 24 / `md` 32 / `lg` 40) rather than
2815
+ * an option, and it is the *outer* height, so an `md` stepper lines up with a
2816
+ * 32px field. The buttons are square at it: `md` and `lg` clear the 24×24
2817
+ * pointer target of WCAG 2.2 SC 2.5.8, while `sm` leaves 22px inside its border
2818
+ * and is therefore the dense desktop option.
2819
+ */
2820
+ interface UniQuantityStepperOptions {
2821
+ color?: ContainerColorToken;
2822
+ border?: Border;
2823
+ borderRadius?: Radius;
2824
+ /**
2825
+ * Colour override for the rules between the buttons and the value. Unset —
2826
+ * the default — means they take `border`, so the frame reads as one weight
2827
+ * and the dividers follow the focus border. Set this only for a deliberately
2828
+ * distinct divider.
2829
+ */
2830
+ dividerColor?: ColorKey;
2831
+ incrementIcon?: IconName;
2832
+ decrementIcon?: IconName;
2833
+ /** Replaces the decrement glyph at `min` when `deleteAtMin` is set. */
2834
+ deleteIcon?: IconName;
2835
+ /** `font-variant-numeric: tabular-nums`, so held stepping does not jitter. */
2836
+ tabularNumerals?: boolean;
2837
+ /** Minimum width of the value, e.g. `'3ch'`. Stops a step reflowing the row. */
2838
+ valueWidth?: string | number;
2839
+ }
2840
+
2841
+ /**
2842
+ * `− 3 +` for cart lines, table cells and seat counts: the numeric core with no
2843
+ * field chrome, no label and no room for either.
2844
+ *
2845
+ * A separate component rather than a `chrome="bare"` flag on
2846
+ * `uni-number-input`, because this control is defined by what it does *not*
2847
+ * have — presets, affixes, expressions, four stepper layouts — and eight inputs
2848
+ * are easier to write correctly than forty with a list of which ones to leave
2849
+ * alone. The arithmetic, parsing and hold-to-repeat are the cdk's, shared with
2850
+ * the field, so `1,200` and the keyboard map behave identically in both.
2851
+ *
2852
+ * The middle stays a real input by default: typing `12` beats tapping `+`
2853
+ * eleven times. `editable=false` is for read-mostly tables.
2854
+ */
2855
+ declare class UniQuantityStepperComponent extends BaseComponent<UniQuantityStepperOptions> implements FormValueControl<number | null> {
2856
+ readonly value: _angular_core.ModelSignal<number>;
2857
+ readonly disabled: _angular_core.InputSignal<boolean>;
2858
+ readonly touched: _angular_core.ModelSignal<boolean>;
2859
+ readonly invalid: _angular_core.InputSignal<boolean>;
2860
+ readonly dirty: _angular_core.InputSignal<boolean>;
2861
+ readonly required: _angular_core.InputSignal<boolean>;
2862
+ readonly ariaDescribedBy: _angular_core.InputSignal<string>;
2863
+ /**
2864
+ * Accessible name. Never visible and always needed — a cart with six of these
2865
+ * needs "Quantity, Blue T-shirt (M)", not six controls called "Quantity".
2866
+ */
2867
+ label: _angular_core.InputSignal<string>;
2868
+ min: _angular_core.InputSignal<number>;
2869
+ max: _angular_core.InputSignal<number>;
2870
+ step: _angular_core.InputSignal<number>;
2871
+ size: _angular_core.InputSignal<Size>;
2872
+ /** `false` renders the number as text: read-mostly tables. */
2873
+ editable: _angular_core.InputSignal<boolean>;
2874
+ /**
2875
+ * The cart pattern in one attribute: at `min` the decrement button becomes a
2876
+ * remove affordance and emits `removed` rather than stepping. Without it
2877
+ * every shop reimplements the same `value === 1 ? remove() : step(-1)` branch
2878
+ * outside the component.
2879
+ */
2880
+ deleteAtMin: _angular_core.InputSignal<boolean>;
2881
+ /**
2882
+ * The remove affordance was activated — the row should come out.
2883
+ *
2884
+ * Named `removed`, not the spec's `emptied`: that word is a native
2885
+ * `HTMLMediaElement` event, which `@angular-eslint/no-output-native` bans for
2886
+ * good reason, and `removed` is already what `uni-tag` calls this same
2887
+ * request.
2888
+ */
2889
+ removed: _angular_core.OutputEmitterRef<void>;
2890
+ private readonly inputRef;
2891
+ protected readonly srOnly: string;
2892
+ protected readonly announcer: _uni_design_system_uni_angular.Announcer;
2893
+ protected readonly hintId: string;
2894
+ /** Uncommitted text. `null` means "show the committed value". */
2895
+ private readonly draft;
2896
+ private readonly canonical;
2897
+ /** Quantities are plain numbers; precision follows the step. */
2898
+ protected readonly format: _angular_core.Signal<_uni_design_system_uni_angular.UniResolvedNumberFormat>;
2899
+ protected readonly displayText: _angular_core.Signal<string>;
2900
+ protected readonly showError: _angular_core.Signal<boolean>;
2901
+ protected readonly describedBy: _angular_core.Signal<string>;
2902
+ /** A quantity has a floor even when a validator has not supplied one. */
1810
2903
  protected readonly resolvedMin: _angular_core.Signal<number>;
1811
- protected readonly resolvedMax: _angular_core.Signal<number>;
1812
- markAsTouched(): void;
1813
- handleInput(event: Event): void;
1814
- protected readonly fillPercent: _angular_core.Signal<string>;
2904
+ protected readonly atMin: _angular_core.Signal<boolean>;
2905
+ protected readonly atMax: _angular_core.Signal<boolean>;
2906
+ /** At the floor with `deleteAtMin`, the − is a remove control instead. */
2907
+ protected readonly showDelete: _angular_core.Signal<boolean>;
2908
+ protected readonly decrementIcon: _angular_core.Signal<_uni_design_system_uni_core.IconName>;
2909
+ protected readonly decrementLabel: _angular_core.Signal<string>;
2910
+ protected onInput(text: string): void;
2911
+ /**
2912
+ * The same parse path as the field, so `1,200` commits as 1200 here too.
2913
+ * Unreadable text reverts rather than being kept: this control has no room to
2914
+ * show an error, and no `rejected` output to report one through.
2915
+ */
2916
+ protected commitDraft(): void;
2917
+ protected applyStep(direction: 1 | -1, announce?: boolean): void;
2918
+ /**
2919
+ * The decrement button has two jobs. Below the floor with `deleteAtMin` it is
2920
+ * a remove control — a single click, with nothing to hold and repeat — so the
2921
+ * press/repeat machinery is skipped entirely in that state.
2922
+ */
2923
+ protected onDecrementPress(event: PointerEvent): void;
2924
+ protected onDecrementClick(): void;
2925
+ private announceValue;
2926
+ private announceFence;
2927
+ /** Announced on release only; narrating every intermediate value is noise. */
2928
+ protected readonly increment: _uni_design_system_uni_angular.PressRepeat;
2929
+ protected readonly decrement: _uni_design_system_uni_angular.PressRepeat;
2930
+ protected onKeydown(event: KeyboardEvent): void;
2931
+ protected onBlur(): void;
2932
+ protected focusField(): void;
2933
+ protected readonly className: _angular_core.Signal<string>;
2934
+ /** Overall height, from the theme's `sizes` block. */
2935
+ private readonly height;
2936
+ /**
2937
+ * The shared field chrome, read from the same `input` theme entry
2938
+ * `uni-input-box` resolves. This control has its own container tokens, but the
2939
+ * **focus indicator** has to be the one every other field uses — a stepper
2940
+ * that highlights differently from the field beside it reads as a bug.
2941
+ */
2942
+ private readonly fieldChrome;
2943
+ protected readonly rootClass: _angular_core.Signal<string>;
2944
+ /** Square at the field height, so the pointer target is legal at every size. */
2945
+ protected readonly buttonClass: _angular_core.Signal<string>;
2946
+ /** The rules either side of the value, matching the frame around it. */
2947
+ private readonly dividerBorder;
2948
+ private valueBase;
1815
2949
  protected readonly inputClass: _angular_core.Signal<string>;
1816
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<UniSliderComponent, never>;
1817
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<UniSliderComponent, "uni-slider", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "dirty": { "alias": "dirty"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "ariaDescribedBy": { "alias": "ariaDescribedBy"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": true; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "step": { "alias": "step"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touched": "touchedChange"; }, never, never, true, never>;
2950
+ /** Read-only presentation: centred text on the same grid as the input. */
2951
+ protected readonly readoutClass: _angular_core.Signal<string>;
2952
+ protected readonly glyphSize: _angular_core.Signal<number>;
2953
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<UniQuantityStepperComponent, never>;
2954
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<UniQuantityStepperComponent, "uni-quantity-stepper, QuantityStepper", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "dirty": { "alias": "dirty"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "ariaDescribedBy": { "alias": "ariaDescribedBy"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": true; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "step": { "alias": "step"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "editable": { "alias": "editable"; "required": false; "isSignal": true; }; "deleteAtMin": { "alias": "deleteAtMin"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touched": "touchedChange"; "removed": "removed"; }, never, never, true, never>;
1818
2955
  }
1819
2956
 
1820
2957
  /**
@@ -1951,6 +3088,13 @@ declare class UniTagInputComponent extends BaseComponent<UniTagInputOptions> imp
1951
3088
  has the same geometry but is only the fallback's positioning context. */
1952
3089
  protected readonly className: _angular_core.Signal<string>;
1953
3090
  protected readonly wrapperClass: _angular_core.Signal<string>;
3091
+ /**
3092
+ * The shared field chrome, from the same `input` theme entry
3093
+ * `uni-input-box` resolves — not a duplicate token, because the inset has to
3094
+ * match every other field or a chip field stops lining up with the text
3095
+ * field above it.
3096
+ */
3097
+ private readonly fieldChrome;
1954
3098
  protected readonly fieldClass: _angular_core.Signal<string>;
1955
3099
  protected readonly inputClass: _angular_core.Signal<string>;
1956
3100
  protected readonly listClass: _angular_core.Signal<string>;
@@ -2182,7 +3326,7 @@ declare class UniToggleComponent extends BaseComponent<UniToggleOptions> impleme
2182
3326
  */
2183
3327
  declare const UNI_LAYOUT: readonly [typeof UniBoxDirective, typeof UniRowDirective, typeof UniStackDirective, typeof UniCenterDirective, typeof UniWrapDirective, typeof UniGridDirective, typeof UniGridAreaDirective, typeof UniTextDirective];
2184
3328
  /** Every form control, for `imports: [...UNI_FORMS]`. */
2185
- declare const UNI_FORMS: readonly [typeof UniInputComponent, typeof UniInputBoxComponent, typeof UniTextareaComponent, typeof UniSelectComponent, typeof UniCheckboxComponent, typeof UniRadioComponent, typeof UniToggleComponent, typeof UniComboboxComponent, typeof UniMultiSelectComponent, typeof UniMultiSelectDropdownComponent, typeof UniSearchInputComponent, typeof UniTagInputComponent, typeof UniSliderComponent, typeof UniDateInputComponent, typeof UniTimeInputComponent, typeof UniDateTimeInputComponent];
3329
+ declare const UNI_FORMS: readonly [typeof UniInputComponent, typeof UniInputBoxComponent, typeof UniTextareaComponent, typeof UniSelectComponent, typeof UniCheckboxComponent, typeof UniRadioComponent, typeof UniToggleComponent, typeof UniComboboxComponent, typeof UniMultiSelectComponent, typeof UniMultiSelectDropdownComponent, typeof UniSearchInputComponent, typeof UniTagInputComponent, typeof UniNumberInputComponent, typeof UniNumberRangeInputComponent, typeof UniQuantityStepperComponent, typeof UniSliderComponent, typeof UniDateInputComponent, typeof UniTimeInputComponent, typeof UniDateTimeInputComponent];
2186
3330
 
2187
3331
  /** Theme-level options for `uni-app-bar`, resolved by token name. */
2188
3332
  interface UniAppBarOptions {
@@ -2448,7 +3592,7 @@ declare class UniCalendarComponent extends BaseComponent<UniCalendarOptions> imp
2448
3592
  /** BCP 47 tag; defaults to the document language, then the browser's. */
2449
3593
  locale: _angular_core.InputSignal<string>;
2450
3594
  /** First day of week, 0 = Sunday; defaults from the locale's week info. */
2451
- weekStart: _angular_core.InputSignal<0 | 1 | 2 | 3 | 4 | 6 | 5>;
3595
+ weekStart: _angular_core.InputSignal<0 | 1 | 2 | 3 | 4 | 5 | 6>;
2452
3596
  /** Names the grid when it stands alone (otherwise the heading names it). */
2453
3597
  ariaLabel: _angular_core.InputSignal<string>;
2454
3598
  /** Day geometry token; `sm`/`md`/`lg` map to the theme's `calendar` sizes. */
@@ -4456,5 +5600,5 @@ declare class DragAndDropDirective {
4456
5600
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<DragAndDropDirective, "[uni-drag-n-drop], [dragAndDrop]", never, {}, { "fileDropped": "fileDropped"; }, never, never, true, never>;
4457
5601
  }
4458
5602
 
4459
- export { BodyRenderDirective, ConfirmationDialogComponent, DragAndDropDirective, FOCUSABLE_SELECTOR, ListboxNavigation, LocalStorageService, NotificationService, NotificationsComponent, RippleDirective, TRANSFORM_ORIGINS, ThemeService, UNI_FORMS, UNI_LAYOUT, UNI_THEMES, UniAlertComponent, UniAppBarComponent, UniAvatarComponent, UniAvatarGroupComponent, UniBackgroundComponent, UniBadgeComponent, UniBaseDatasource, UniBoxDirective, UniBreadcrumbComponent, UniButtonComponent, UniButtonGroupComponent, UniCalendarComponent, UniCalloutComponent, UniCardComponent, UniCardContentComponent, UniCardHeaderComponent, UniCenterDirective, UniCheckboxComponent, UniComboboxComponent, UniDataSearchComponent, UniDataTableComponent, UniDateInputComponent, UniDateTimeInputComponent, UniDebounceInputComponent, UniDialogButtonsComponent, UniDialogComponent, UniDialogHeaderComponent, UniDividerComponent, UniDrawerComponent, UniDropdownComponent, UniExpandAreaComponent, UniExpandComponent, UniExpandToggleComponent, UniFileDropZoneComponent, UniGridAreaDirective, UniGridDirective, UniIconButtonComponent, UniIconComponent, UniInputBoxComponent, UniInputComponent, UniJsonViewComponent, UniMenuComponent, UniMultiSelectComponent, UniMultiSelectDropdownComponent, UniNotificationBadgeComponent, UniPaginatorComponent, UniPopoverComponent, UniProgressBarComponent, UniProgressGaugeComponent, UniRadioComponent, UniRecordDatasource, UniRowDirective, UniScrollAreaComponent, UniSearchInputComponent, UniSelectComponent, UniServerSideDatasource, UniSkeletonComponent, UniSliderComponent, UniSnackbarComponent, UniSortHeaderComponent, UniStackDirective, UniStatComponent, UniSymbolComponent, UniTabComponent, UniTabsComponent, UniTagComponent, UniTagInputComponent, UniTextDirective, UniTextareaComponent, UniThemeBuilderComponent, UniThemeSwitchComponent, UniTimeInputComponent, UniToggleComponent, UniTooltipComponent, UniTourComponent, UniWrapDirective, acceptableFile, addDays, addMonths, anchorArrowStyles, anchorStyles, buildMonthGrid, clearAnchorName, createAnnouncer, createListboxNavigation, dayOfWeek, daysInMonth, discreteOverlayTransition, focusableElements, formatDate, formatMonthHeading, formatTime, getFileExtension, inclusiveDayCount, isDivider, isToggleOpen, isValidDate, isoDate, joinDateTime, listboxPopupAttr, listboxPopupStyles, localeDatePlaceholder, localeDefaultHour12, localeFieldOrder, localeMonthNames, localeWeekStart, monthOf, motionSafe, newAnchorName, newListboxAnchor, parseDateText, parseTimeText, promoteListboxPopup, resolveElement, resolveFocusTarget, restoreOverlayFocus, setAnchorName, splitDateTime, spotlightStyles, supportsAnchoredPopup, timeSlots, todayIso, transformOriginFor, uniqueId, useTimer, visuallyHidden, weekdayNames };
4460
- export type { Alert, AnchorOffset, AnchorRect, Announcer, BrandPaletteConfig, BreadcrumbItem, ButtonGroupConfig, ButtonGroupItem, ColumnDefinition, Confirmation, DataLoader, DrawerMode, DrawerPosition, ImagePosition, ListboxNavigationConfig, MenuDivider, MenuItem, MenuItemWithLabel, MenuItemWithTemplate, Option, Options, PageRequest, PageResponse, Placement, ScrollbarAppearance, SkeletonShape, SkeletonSweepDirection, Snackbar, Sort, SortDirection, SpotlightOptions, SpotlightStyles, UniAppBarOptions, UniAvatarGroupOptions, UniAvatarOptions, UniBreadcrumbOptions, UniCalendarMarker, UniCalendarMode, UniCalendarOptions, UniCalendarValue, UniCalloutDismissal, UniCalloutOptions, UniCheckboxOptions, UniComboboxOptions, UniComboboxRejection, UniDataSearchOptions, UniDataTableOptions, UniDatasource, UniDate, UniDateInputOptions, UniDateInputRejection, UniDateRange, UniDateTime, UniDateTimeInputOptions, UniDrawerOptions, UniExpandOptions, UniInputBoxOptions, UniInputMode, UniInputType, UniListboxPopupOptions, UniMenuItemOptions, UniMenuOptions, UniMonthGridCell, UniMultiSelectDropdownOptions, UniNotificationBadgeOptions, UniPaginatorOptions, UniPopoverOptions, UniRadioOption, UniRadioOptions, UniSearchInputOptions, UniSkeletonOptions, UniSliderOptions, UniStatOptions, UniTabsOptions, UniTagInputOptions, UniTagItem, UniTagOptions, UniTagRejection, UniTagSuggestion, UniTagValue, UniTextareaOptions, UniTime, UniTimeInputOptions, UniTimeInputRejection, UniToggleOptions, UniTourAdvance, UniTourOptions, UniTourStep, UniWeekdayName };
5603
+ export { BodyRenderDirective, ConfirmationDialogComponent, DragAndDropDirective, FOCUSABLE_SELECTOR, ListboxNavigation, LocalStorageService, NotificationService, NotificationsComponent, RippleDirective, TRANSFORM_ORIGINS, ThemeService, UNI_FORMS, UNI_LAYOUT, UNI_THEMES, UniAlertComponent, UniAppBarComponent, UniAvatarComponent, UniAvatarGroupComponent, UniBackgroundComponent, UniBadgeComponent, UniBaseDatasource, UniBoxDirective, UniBreadcrumbComponent, UniButtonComponent, UniButtonGroupComponent, UniCalendarComponent, UniCalloutComponent, UniCardComponent, UniCardContentComponent, UniCardHeaderComponent, UniCenterDirective, UniCheckboxComponent, UniComboboxComponent, UniDataSearchComponent, UniDataTableComponent, UniDateInputComponent, UniDateTimeInputComponent, UniDebounceInputComponent, UniDialogButtonsComponent, UniDialogComponent, UniDialogHeaderComponent, UniDividerComponent, UniDrawerComponent, UniDropdownComponent, UniExpandAreaComponent, UniExpandComponent, UniExpandToggleComponent, UniFileDropZoneComponent, UniGridAreaDirective, UniGridDirective, UniIconButtonComponent, UniIconComponent, UniInputBoxComponent, UniInputComponent, UniJsonViewComponent, UniMenuComponent, UniMultiSelectComponent, UniMultiSelectDropdownComponent, UniNotificationBadgeComponent, UniNumberInputComponent, UniNumberRangeInputComponent, UniPaginatorComponent, UniPopoverComponent, UniProgressBarComponent, UniProgressGaugeComponent, UniQuantityStepperComponent, UniRadioComponent, UniRecordDatasource, UniRowDirective, UniScrollAreaComponent, UniSearchInputComponent, UniSelectComponent, UniServerSideDatasource, UniSkeletonComponent, UniSliderComponent, UniSnackbarComponent, UniSortHeaderComponent, UniStackDirective, UniStatComponent, UniSymbolComponent, UniTabComponent, UniTabsComponent, UniTagComponent, UniTagInputComponent, UniTextDirective, UniTextareaComponent, UniThemeBuilderComponent, UniThemeSwitchComponent, UniTimeInputComponent, UniToggleComponent, UniTooltipComponent, UniTourComponent, UniWrapDirective, acceptableFile, addDays, addMonths, anchorArrowStyles, anchorStyles, buildMonthGrid, clampDecimal, clearAnchorName, compareDecimal, createAnnouncer, createListboxNavigation, createPressRepeat, dayOfWeek, daysInMonth, decimalScale, discreteOverlayTransition, evaluateExpression, focusableElements, formatDate, formatMonthHeading, formatNumber, formatTime, fromScaled, getFileExtension, inclusiveDayCount, isCanonicalDecimal, isDivider, isToggleOpen, isValidDate, isoDate, joinDateTime, listboxPopupAttr, listboxPopupStyles, localeDatePlaceholder, localeDefaultHour12, localeFieldOrder, localeMonthNames, localeNumberParts, localeWeekStart, losesPrecision, monthOf, motionSafe, newAnchorName, newListboxAnchor, normalizeDecimal, parseDateText, parseNumber, parseTimeText, promoteListboxPopup, rawNumberText, resolveElement, resolveFocusTarget, resolveNumberFormat, restoreOverlayFocus, roundDecimal, setAnchorName, settleNumber, shiftDecimal, speakNumber, splitDateTime, spotlightStyles, stepDecimal, supportsAnchoredPopup, timeSlots, toAsciiDigits, toDecimal, toNumber, toScaled, todayIso, transformOriginFor, uniqueId, useTimer, visuallyHidden, weekdayNames };
5604
+ export type { Alert, AnchorOffset, AnchorRect, Announcer, BrandPaletteConfig, BreadcrumbItem, ButtonGroupConfig, ButtonGroupItem, ColumnDefinition, Confirmation, DataLoader, DrawerMode, DrawerPosition, ImagePosition, ListboxNavigationConfig, MenuDivider, MenuItem, MenuItemWithLabel, MenuItemWithTemplate, Option, Options, PageRequest, PageResponse, Placement, PressRepeat, PressRepeatConfig, PressRepeatTiming, ScrollbarAppearance, SkeletonShape, SkeletonSweepDirection, Snackbar, Sort, SortDirection, SpotlightOptions, SpotlightStyles, UniAppBarOptions, UniAvatarGroupOptions, UniAvatarOptions, UniBreadcrumbOptions, UniCalendarMarker, UniCalendarMode, UniCalendarOptions, UniCalendarValue, UniCalloutDismissal, UniCalloutOptions, UniCheckboxOptions, UniComboboxOptions, UniComboboxRejection, UniDataSearchOptions, UniDataTableOptions, UniDatasource, UniDate, UniDateInputOptions, UniDateInputRejection, UniDateRange, UniDateTime, UniDateTimeInputOptions, UniDrawerOptions, UniExpandOptions, UniInputBoxOptions, UniInputMode, UniInputType, UniListboxPopupOptions, UniLocaleNumberParts, UniMenuItemOptions, UniMenuOptions, UniMonthGridCell, UniMultiSelectDropdownOptions, UniNotificationBadgeOptions, UniNumberClamp, UniNumberFormatConfig, UniNumberGrouping, UniNumberInputOptions, UniNumberParseResult, UniNumberPreset, UniNumberRange, UniNumberRangeInputOptions, UniNumberRangePart, UniNumberRangeRejection, UniNumberRejectReason, UniNumberRejection, UniNumberStepConfig, UniNumberStepped, UniPaginatorOptions, UniPopoverOptions, UniQuantityStepperOptions, UniRadioOption, UniRadioOptions, UniResolvedNumberFormat, UniRoundingMode, UniSearchInputOptions, UniSkeletonOptions, UniSliderMark, UniSliderOptions, UniSliderThumb, UniStatOptions, UniStepperLayout, UniTabsOptions, UniTagInputOptions, UniTagItem, UniTagOptions, UniTagRejection, UniTagSuggestion, UniTagValue, UniTextareaOptions, UniTime, UniTimeInputOptions, UniTimeInputRejection, UniToggleOptions, UniTourAdvance, UniTourOptions, UniTourStep, UniWeekdayName };