twico-ui 1.46.0 → 1.47.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.cts CHANGED
@@ -1636,6 +1636,34 @@ interface ColorPickerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "o
1636
1636
  label?: React.ReactNode;
1637
1637
  /** Helper text shown below when there is no error. */
1638
1638
  hint?: React.ReactNode;
1639
+ /**
1640
+ * #494: always render the footer lane, empty when there is nothing to say, so this field is the
1641
+ * same height as one that has a `hint`, an `error` or a counter.
1642
+ *
1643
+ * A row of fields aligned with `align="flex-end"` splits onto two lines the moment ONE of them
1644
+ * has a hint: that field grows a footer, the others do not, and the caption ends up moving a
1645
+ * *different* control. `align` cannot fix it - `flex-start` lines up the labels instead, so the
1646
+ * controls part company as soon as one label wraps at a narrow width.
1647
+ *
1648
+ * Set it per field, or once on any ancestor for everything inside, which is the safer habit in a
1649
+ * row - with a per-field prop alone, adding a field later and forgetting it brings the
1650
+ * misalignment straight back:
1651
+ *
1652
+ * ```jsx
1653
+ * <Stack direction="row" align="flex-end" data-reserve-footer>
1654
+ * <Select label="Filter" … />
1655
+ * <Select label="Comparison" hint="Matches the whole value." … />
1656
+ * <Input label="Value" … />
1657
+ * </Stack>
1658
+ * ```
1659
+ *
1660
+ * The lane is held open by generated content, so it matches the real footer by construction -
1661
+ * same font metrics, same flex gap - rather than by a height that drifts when a token changes.
1662
+ * It adds no text to the accessibility tree.
1663
+ *
1664
+ * @default false
1665
+ */
1666
+ reserveFooter?: boolean;
1639
1667
  /** Error message — turns the field red and replaces the hint. */
1640
1668
  error?: React.ReactNode;
1641
1669
  /** Marks the field required (adds an asterisk to the label). @default false */
@@ -1696,6 +1724,34 @@ interface OptionGroup {
1696
1724
  interface ComboboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "size" | "value" | "defaultValue" | "onChange"> {
1697
1725
  label?: React.ReactNode;
1698
1726
  hint?: React.ReactNode;
1727
+ /**
1728
+ * #494: always render the footer lane, empty when there is nothing to say, so this field is the
1729
+ * same height as one that has a `hint`, an `error` or a counter.
1730
+ *
1731
+ * A row of fields aligned with `align="flex-end"` splits onto two lines the moment ONE of them
1732
+ * has a hint: that field grows a footer, the others do not, and the caption ends up moving a
1733
+ * *different* control. `align` cannot fix it - `flex-start` lines up the labels instead, so the
1734
+ * controls part company as soon as one label wraps at a narrow width.
1735
+ *
1736
+ * Set it per field, or once on any ancestor for everything inside, which is the safer habit in a
1737
+ * row - with a per-field prop alone, adding a field later and forgetting it brings the
1738
+ * misalignment straight back:
1739
+ *
1740
+ * ```jsx
1741
+ * <Stack direction="row" align="flex-end" data-reserve-footer>
1742
+ * <Select label="Filter" … />
1743
+ * <Select label="Comparison" hint="Matches the whole value." … />
1744
+ * <Input label="Value" … />
1745
+ * </Stack>
1746
+ * ```
1747
+ *
1748
+ * The lane is held open by generated content, so it matches the real footer by construction -
1749
+ * same font metrics, same flex gap - rather than by a height that drifts when a token changes.
1750
+ * It adds no text to the accessibility tree.
1751
+ *
1752
+ * @default false
1753
+ */
1754
+ reserveFooter?: boolean;
1699
1755
  error?: React.ReactNode;
1700
1756
  required?: boolean;
1701
1757
  size?: "sm" | "md" | "lg";
@@ -1825,6 +1881,34 @@ interface CurrencyProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>
1825
1881
  label?: React.ReactNode;
1826
1882
  /** Helper text below the field; linked to the input via aria-describedby. */
1827
1883
  hint?: React.ReactNode;
1884
+ /**
1885
+ * #494: always render the footer lane, empty when there is nothing to say, so this field is the
1886
+ * same height as one that has a `hint`, an `error` or a counter.
1887
+ *
1888
+ * A row of fields aligned with `align="flex-end"` splits onto two lines the moment ONE of them
1889
+ * has a hint: that field grows a footer, the others do not, and the caption ends up moving a
1890
+ * *different* control. `align` cannot fix it - `flex-start` lines up the labels instead, so the
1891
+ * controls part company as soon as one label wraps at a narrow width.
1892
+ *
1893
+ * Set it per field, or once on any ancestor for everything inside, which is the safer habit in a
1894
+ * row - with a per-field prop alone, adding a field later and forgetting it brings the
1895
+ * misalignment straight back:
1896
+ *
1897
+ * ```jsx
1898
+ * <Stack direction="row" align="flex-end" data-reserve-footer>
1899
+ * <Select label="Filter" … />
1900
+ * <Select label="Comparison" hint="Matches the whole value." … />
1901
+ * <Input label="Value" … />
1902
+ * </Stack>
1903
+ * ```
1904
+ *
1905
+ * The lane is held open by generated content, so it matches the real footer by construction -
1906
+ * same font metrics, same flex gap - rather than by a height that drifts when a token changes.
1907
+ * It adds no text to the accessibility tree.
1908
+ *
1909
+ * @default false
1910
+ */
1911
+ reserveFooter?: boolean;
1828
1912
  /** Error text below the field; sets aria-invalid and is linked via aria-describedby (takes precedence over hint). */
1829
1913
  error?: React.ReactNode;
1830
1914
  /** Intercepted to render the label asterisk, and forwarded to the native input as `required`. @default false */
@@ -1865,6 +1949,34 @@ interface CurrencyFieldProps extends Omit<React.InputHTMLAttributes<HTMLInputEle
1865
1949
  label?: React.ReactNode;
1866
1950
  /** Helper text below the field; linked to the input via aria-describedby. */
1867
1951
  hint?: React.ReactNode;
1952
+ /**
1953
+ * #494: always render the footer lane, empty when there is nothing to say, so this field is the
1954
+ * same height as one that has a `hint`, an `error` or a counter.
1955
+ *
1956
+ * A row of fields aligned with `align="flex-end"` splits onto two lines the moment ONE of them
1957
+ * has a hint: that field grows a footer, the others do not, and the caption ends up moving a
1958
+ * *different* control. `align` cannot fix it - `flex-start` lines up the labels instead, so the
1959
+ * controls part company as soon as one label wraps at a narrow width.
1960
+ *
1961
+ * Set it per field, or once on any ancestor for everything inside, which is the safer habit in a
1962
+ * row - with a per-field prop alone, adding a field later and forgetting it brings the
1963
+ * misalignment straight back:
1964
+ *
1965
+ * ```jsx
1966
+ * <Stack direction="row" align="flex-end" data-reserve-footer>
1967
+ * <Select label="Filter" … />
1968
+ * <Select label="Comparison" hint="Matches the whole value." … />
1969
+ * <Input label="Value" … />
1970
+ * </Stack>
1971
+ * ```
1972
+ *
1973
+ * The lane is held open by generated content, so it matches the real footer by construction -
1974
+ * same font metrics, same flex gap - rather than by a height that drifts when a token changes.
1975
+ * It adds no text to the accessibility tree.
1976
+ *
1977
+ * @default false
1978
+ */
1979
+ reserveFooter?: boolean;
1868
1980
  /** Error text below the field; sets aria-invalid and is linked via aria-describedby (takes precedence over hint). */
1869
1981
  error?: React.ReactNode;
1870
1982
  /** Intercepted to render the label asterisk, and forwarded to the native input as `required`. @default false */
@@ -3053,6 +3165,34 @@ interface DatePickerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "on
3053
3165
  label?: React.ReactNode;
3054
3166
  /** Helper text shown below when there is no error. */
3055
3167
  hint?: React.ReactNode;
3168
+ /**
3169
+ * #494: always render the footer lane, empty when there is nothing to say, so this field is the
3170
+ * same height as one that has a `hint`, an `error` or a counter.
3171
+ *
3172
+ * A row of fields aligned with `align="flex-end"` splits onto two lines the moment ONE of them
3173
+ * has a hint: that field grows a footer, the others do not, and the caption ends up moving a
3174
+ * *different* control. `align` cannot fix it - `flex-start` lines up the labels instead, so the
3175
+ * controls part company as soon as one label wraps at a narrow width.
3176
+ *
3177
+ * Set it per field, or once on any ancestor for everything inside, which is the safer habit in a
3178
+ * row - with a per-field prop alone, adding a field later and forgetting it brings the
3179
+ * misalignment straight back:
3180
+ *
3181
+ * ```jsx
3182
+ * <Stack direction="row" align="flex-end" data-reserve-footer>
3183
+ * <Select label="Filter" … />
3184
+ * <Select label="Comparison" hint="Matches the whole value." … />
3185
+ * <Input label="Value" … />
3186
+ * </Stack>
3187
+ * ```
3188
+ *
3189
+ * The lane is held open by generated content, so it matches the real footer by construction -
3190
+ * same font metrics, same flex gap - rather than by a height that drifts when a token changes.
3191
+ * It adds no text to the accessibility tree.
3192
+ *
3193
+ * @default false
3194
+ */
3195
+ reserveFooter?: boolean;
3056
3196
  /** Error message — turns the field red and replaces the hint. */
3057
3197
  error?: React.ReactNode;
3058
3198
  /** Marks the field required (adds an asterisk to the label). @default false */
@@ -3106,6 +3246,34 @@ interface DateRangePickerProps extends Omit<React.HTMLAttributes<HTMLDivElement>
3106
3246
  label?: React.ReactNode;
3107
3247
  /** Helper text shown below when there is no error. */
3108
3248
  hint?: React.ReactNode;
3249
+ /**
3250
+ * #494: always render the footer lane, empty when there is nothing to say, so this field is the
3251
+ * same height as one that has a `hint`, an `error` or a counter.
3252
+ *
3253
+ * A row of fields aligned with `align="flex-end"` splits onto two lines the moment ONE of them
3254
+ * has a hint: that field grows a footer, the others do not, and the caption ends up moving a
3255
+ * *different* control. `align` cannot fix it - `flex-start` lines up the labels instead, so the
3256
+ * controls part company as soon as one label wraps at a narrow width.
3257
+ *
3258
+ * Set it per field, or once on any ancestor for everything inside, which is the safer habit in a
3259
+ * row - with a per-field prop alone, adding a field later and forgetting it brings the
3260
+ * misalignment straight back:
3261
+ *
3262
+ * ```jsx
3263
+ * <Stack direction="row" align="flex-end" data-reserve-footer>
3264
+ * <Select label="Filter" … />
3265
+ * <Select label="Comparison" hint="Matches the whole value." … />
3266
+ * <Input label="Value" … />
3267
+ * </Stack>
3268
+ * ```
3269
+ *
3270
+ * The lane is held open by generated content, so it matches the real footer by construction -
3271
+ * same font metrics, same flex gap - rather than by a height that drifts when a token changes.
3272
+ * It adds no text to the accessibility tree.
3273
+ *
3274
+ * @default false
3275
+ */
3276
+ reserveFooter?: boolean;
3109
3277
  /** Error message — turns the field red and replaces the hint. */
3110
3278
  error?: React.ReactNode;
3111
3279
  /** Marks the field required (adds an asterisk to the label). @default false */
@@ -3163,6 +3331,34 @@ interface TimePickerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "on
3163
3331
  label?: React.ReactNode;
3164
3332
  /** Helper text shown below when there is no error. */
3165
3333
  hint?: React.ReactNode;
3334
+ /**
3335
+ * #494: always render the footer lane, empty when there is nothing to say, so this field is the
3336
+ * same height as one that has a `hint`, an `error` or a counter.
3337
+ *
3338
+ * A row of fields aligned with `align="flex-end"` splits onto two lines the moment ONE of them
3339
+ * has a hint: that field grows a footer, the others do not, and the caption ends up moving a
3340
+ * *different* control. `align` cannot fix it - `flex-start` lines up the labels instead, so the
3341
+ * controls part company as soon as one label wraps at a narrow width.
3342
+ *
3343
+ * Set it per field, or once on any ancestor for everything inside, which is the safer habit in a
3344
+ * row - with a per-field prop alone, adding a field later and forgetting it brings the
3345
+ * misalignment straight back:
3346
+ *
3347
+ * ```jsx
3348
+ * <Stack direction="row" align="flex-end" data-reserve-footer>
3349
+ * <Select label="Filter" … />
3350
+ * <Select label="Comparison" hint="Matches the whole value." … />
3351
+ * <Input label="Value" … />
3352
+ * </Stack>
3353
+ * ```
3354
+ *
3355
+ * The lane is held open by generated content, so it matches the real footer by construction -
3356
+ * same font metrics, same flex gap - rather than by a height that drifts when a token changes.
3357
+ * It adds no text to the accessibility tree.
3358
+ *
3359
+ * @default false
3360
+ */
3361
+ reserveFooter?: boolean;
3166
3362
  /** Error message — turns the field red and replaces the hint. */
3167
3363
  error?: React.ReactNode;
3168
3364
  /** Marks the field required (adds an asterisk to the label). @default false */
@@ -3218,6 +3414,34 @@ interface DateTimePickerProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
3218
3414
  label?: React.ReactNode;
3219
3415
  /** Helper text shown below when there is no error. */
3220
3416
  hint?: React.ReactNode;
3417
+ /**
3418
+ * #494: always render the footer lane, empty when there is nothing to say, so this field is the
3419
+ * same height as one that has a `hint`, an `error` or a counter.
3420
+ *
3421
+ * A row of fields aligned with `align="flex-end"` splits onto two lines the moment ONE of them
3422
+ * has a hint: that field grows a footer, the others do not, and the caption ends up moving a
3423
+ * *different* control. `align` cannot fix it - `flex-start` lines up the labels instead, so the
3424
+ * controls part company as soon as one label wraps at a narrow width.
3425
+ *
3426
+ * Set it per field, or once on any ancestor for everything inside, which is the safer habit in a
3427
+ * row - with a per-field prop alone, adding a field later and forgetting it brings the
3428
+ * misalignment straight back:
3429
+ *
3430
+ * ```jsx
3431
+ * <Stack direction="row" align="flex-end" data-reserve-footer>
3432
+ * <Select label="Filter" … />
3433
+ * <Select label="Comparison" hint="Matches the whole value." … />
3434
+ * <Input label="Value" … />
3435
+ * </Stack>
3436
+ * ```
3437
+ *
3438
+ * The lane is held open by generated content, so it matches the real footer by construction -
3439
+ * same font metrics, same flex gap - rather than by a height that drifts when a token changes.
3440
+ * It adds no text to the accessibility tree.
3441
+ *
3442
+ * @default false
3443
+ */
3444
+ reserveFooter?: boolean;
3221
3445
  /** Error message — recolors both controls and replaces the hint. */
3222
3446
  error?: React.ReactNode;
3223
3447
  /** Marks the field required (adds an asterisk to the label). @default false */
@@ -3275,6 +3499,34 @@ declare function DateTimePicker(props: DateTimePickerProps): React.JSX.Element;
3275
3499
  interface MultiSelectProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "size" | "value" | "defaultValue" | "onChange"> {
3276
3500
  label?: React.ReactNode;
3277
3501
  hint?: React.ReactNode;
3502
+ /**
3503
+ * #494: always render the footer lane, empty when there is nothing to say, so this field is the
3504
+ * same height as one that has a `hint`, an `error` or a counter.
3505
+ *
3506
+ * A row of fields aligned with `align="flex-end"` splits onto two lines the moment ONE of them
3507
+ * has a hint: that field grows a footer, the others do not, and the caption ends up moving a
3508
+ * *different* control. `align` cannot fix it - `flex-start` lines up the labels instead, so the
3509
+ * controls part company as soon as one label wraps at a narrow width.
3510
+ *
3511
+ * Set it per field, or once on any ancestor for everything inside, which is the safer habit in a
3512
+ * row - with a per-field prop alone, adding a field later and forgetting it brings the
3513
+ * misalignment straight back:
3514
+ *
3515
+ * ```jsx
3516
+ * <Stack direction="row" align="flex-end" data-reserve-footer>
3517
+ * <Select label="Filter" … />
3518
+ * <Select label="Comparison" hint="Matches the whole value." … />
3519
+ * <Input label="Value" … />
3520
+ * </Stack>
3521
+ * ```
3522
+ *
3523
+ * The lane is held open by generated content, so it matches the real footer by construction -
3524
+ * same font metrics, same flex gap - rather than by a height that drifts when a token changes.
3525
+ * It adds no text to the accessibility tree.
3526
+ *
3527
+ * @default false
3528
+ */
3529
+ reserveFooter?: boolean;
3278
3530
  error?: React.ReactNode;
3279
3531
  required?: boolean;
3280
3532
  /** Control height preset, matching Select/Combobox. @default "md" */
@@ -3540,6 +3792,34 @@ interface FieldProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "id"> {
3540
3792
  label?: React.ReactNode;
3541
3793
  /** Helper text shown below when there is no error. */
3542
3794
  hint?: React.ReactNode;
3795
+ /**
3796
+ * #494: always render the footer lane, empty when there is nothing to say, so this field is the
3797
+ * same height as one that has a `hint`, an `error` or a counter.
3798
+ *
3799
+ * A row of fields aligned with `align="flex-end"` splits onto two lines the moment ONE of them
3800
+ * has a hint: that field grows a footer, the others do not, and the caption ends up moving a
3801
+ * *different* control. `align` cannot fix it - `flex-start` lines up the labels instead, so the
3802
+ * controls part company as soon as one label wraps at a narrow width.
3803
+ *
3804
+ * Set it per field, or once on any ancestor for everything inside, which is the safer habit in a
3805
+ * row - with a per-field prop alone, adding a field later and forgetting it brings the
3806
+ * misalignment straight back:
3807
+ *
3808
+ * ```jsx
3809
+ * <Stack direction="row" align="flex-end" data-reserve-footer>
3810
+ * <Select label="Filter" … />
3811
+ * <Select label="Comparison" hint="Matches the whole value." … />
3812
+ * <Input label="Value" … />
3813
+ * </Stack>
3814
+ * ```
3815
+ *
3816
+ * The lane is held open by generated content, so it matches the real footer by construction -
3817
+ * same font metrics, same flex gap - rather than by a height that drifts when a token changes.
3818
+ * It adds no text to the accessibility tree.
3819
+ *
3820
+ * @default false
3821
+ */
3822
+ reserveFooter?: boolean;
3543
3823
  /** Error message — replaces the hint and renders in the danger color. */
3544
3824
  error?: React.ReactNode;
3545
3825
  /** Marks the field required (adds an asterisk after the label). @default false */
@@ -3728,6 +4008,34 @@ interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "
3728
4008
  label?: React.ReactNode;
3729
4009
  /** Helper text shown below when there is no error. */
3730
4010
  hint?: React.ReactNode;
4011
+ /**
4012
+ * #494: always render the footer lane, empty when there is nothing to say, so this field is the
4013
+ * same height as one that has a `hint`, an `error` or a counter.
4014
+ *
4015
+ * A row of fields aligned with `align="flex-end"` splits onto two lines the moment ONE of them
4016
+ * has a hint: that field grows a footer, the others do not, and the caption ends up moving a
4017
+ * *different* control. `align` cannot fix it - `flex-start` lines up the labels instead, so the
4018
+ * controls part company as soon as one label wraps at a narrow width.
4019
+ *
4020
+ * Set it per field, or once on any ancestor for everything inside, which is the safer habit in a
4021
+ * row - with a per-field prop alone, adding a field later and forgetting it brings the
4022
+ * misalignment straight back:
4023
+ *
4024
+ * ```jsx
4025
+ * <Stack direction="row" align="flex-end" data-reserve-footer>
4026
+ * <Select label="Filter" … />
4027
+ * <Select label="Comparison" hint="Matches the whole value." … />
4028
+ * <Input label="Value" … />
4029
+ * </Stack>
4030
+ * ```
4031
+ *
4032
+ * The lane is held open by generated content, so it matches the real footer by construction -
4033
+ * same font metrics, same flex gap - rather than by a height that drifts when a token changes.
4034
+ * It adds no text to the accessibility tree.
4035
+ *
4036
+ * @default false
4037
+ */
4038
+ reserveFooter?: boolean;
3731
4039
  /** Error message — turns the field red and replaces the hint. */
3732
4040
  error?: React.ReactNode;
3733
4041
  /** Marks the field required (adds an asterisk and forwards to the native input). */
@@ -4036,6 +4344,34 @@ interface RadioGroupProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "on
4036
4344
  label?: React.ReactNode;
4037
4345
  /** Helper text below the group. */
4038
4346
  hint?: React.ReactNode;
4347
+ /**
4348
+ * #494: always render the footer lane, empty when there is nothing to say, so this field is the
4349
+ * same height as one that has a `hint`, an `error` or a counter.
4350
+ *
4351
+ * A row of fields aligned with `align="flex-end"` splits onto two lines the moment ONE of them
4352
+ * has a hint: that field grows a footer, the others do not, and the caption ends up moving a
4353
+ * *different* control. `align` cannot fix it - `flex-start` lines up the labels instead, so the
4354
+ * controls part company as soon as one label wraps at a narrow width.
4355
+ *
4356
+ * Set it per field, or once on any ancestor for everything inside, which is the safer habit in a
4357
+ * row - with a per-field prop alone, adding a field later and forgetting it brings the
4358
+ * misalignment straight back:
4359
+ *
4360
+ * ```jsx
4361
+ * <Stack direction="row" align="flex-end" data-reserve-footer>
4362
+ * <Select label="Filter" … />
4363
+ * <Select label="Comparison" hint="Matches the whole value." … />
4364
+ * <Input label="Value" … />
4365
+ * </Stack>
4366
+ * ```
4367
+ *
4368
+ * The lane is held open by generated content, so it matches the real footer by construction -
4369
+ * same font metrics, same flex gap - rather than by a height that drifts when a token changes.
4370
+ * It adds no text to the accessibility tree.
4371
+ *
4372
+ * @default false
4373
+ */
4374
+ reserveFooter?: boolean;
4039
4375
  /** Error text below the group; sets `aria-invalid` and is announced once for the whole group. */
4040
4376
  error?: React.ReactNode;
4041
4377
  /** Lay the radios in a column or a wrapping row. @default "vertical" */
@@ -4098,6 +4434,34 @@ declare function Rating(props: RatingProps): React.JSX.Element;
4098
4434
  interface SelectProps extends Omit<React.HTMLAttributes<HTMLButtonElement>, "onChange" | "defaultValue"> {
4099
4435
  label?: React.ReactNode;
4100
4436
  hint?: React.ReactNode;
4437
+ /**
4438
+ * #494: always render the footer lane, empty when there is nothing to say, so this field is the
4439
+ * same height as one that has a `hint`, an `error` or a counter.
4440
+ *
4441
+ * A row of fields aligned with `align="flex-end"` splits onto two lines the moment ONE of them
4442
+ * has a hint: that field grows a footer, the others do not, and the caption ends up moving a
4443
+ * *different* control. `align` cannot fix it - `flex-start` lines up the labels instead, so the
4444
+ * controls part company as soon as one label wraps at a narrow width.
4445
+ *
4446
+ * Set it per field, or once on any ancestor for everything inside, which is the safer habit in a
4447
+ * row - with a per-field prop alone, adding a field later and forgetting it brings the
4448
+ * misalignment straight back:
4449
+ *
4450
+ * ```jsx
4451
+ * <Stack direction="row" align="flex-end" data-reserve-footer>
4452
+ * <Select label="Filter" … />
4453
+ * <Select label="Comparison" hint="Matches the whole value." … />
4454
+ * <Input label="Value" … />
4455
+ * </Stack>
4456
+ * ```
4457
+ *
4458
+ * The lane is held open by generated content, so it matches the real footer by construction -
4459
+ * same font metrics, same flex gap - rather than by a height that drifts when a token changes.
4460
+ * It adds no text to the accessibility tree.
4461
+ *
4462
+ * @default false
4463
+ */
4464
+ reserveFooter?: boolean;
4101
4465
  error?: React.ReactNode;
4102
4466
  required?: boolean;
4103
4467
  size?: "sm" | "md" | "lg";
@@ -4535,6 +4899,34 @@ interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement
4535
4899
  label?: React.ReactNode;
4536
4900
  /** Helper text shown below when there is no error. */
4537
4901
  hint?: React.ReactNode;
4902
+ /**
4903
+ * #494: always render the footer lane, empty when there is nothing to say, so this field is the
4904
+ * same height as one that has a `hint`, an `error` or a counter.
4905
+ *
4906
+ * A row of fields aligned with `align="flex-end"` splits onto two lines the moment ONE of them
4907
+ * has a hint: that field grows a footer, the others do not, and the caption ends up moving a
4908
+ * *different* control. `align` cannot fix it - `flex-start` lines up the labels instead, so the
4909
+ * controls part company as soon as one label wraps at a narrow width.
4910
+ *
4911
+ * Set it per field, or once on any ancestor for everything inside, which is the safer habit in a
4912
+ * row - with a per-field prop alone, adding a field later and forgetting it brings the
4913
+ * misalignment straight back:
4914
+ *
4915
+ * ```jsx
4916
+ * <Stack direction="row" align="flex-end" data-reserve-footer>
4917
+ * <Select label="Filter" … />
4918
+ * <Select label="Comparison" hint="Matches the whole value." … />
4919
+ * <Input label="Value" … />
4920
+ * </Stack>
4921
+ * ```
4922
+ *
4923
+ * The lane is held open by generated content, so it matches the real footer by construction -
4924
+ * same font metrics, same flex gap - rather than by a height that drifts when a token changes.
4925
+ * It adds no text to the accessibility tree.
4926
+ *
4927
+ * @default false
4928
+ */
4929
+ reserveFooter?: boolean;
4538
4930
  /** Error message — turns the field red and replaces the hint. */
4539
4931
  error?: React.ReactNode;
4540
4932
  /** Marks the field required (adds an asterisk and forwards to the native textarea). */