@mond-design-system/react 3.0.2 → 4.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.
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { CSSProperties, HTMLAttributes, JSX, ReactElement, ReactNode, ButtonHTMLAttributes, ElementType, Ref, ComponentPropsWithoutRef, MouseEventHandler, InputHTMLAttributes, TextareaHTMLAttributes, SelectHTMLAttributes, RefObject, KeyboardEvent } from 'react';
2
+ import { CSSProperties, HTMLAttributes, JSX, ReactElement, Ref, ReactNode, ButtonHTMLAttributes, ElementType, ComponentPropsWithRef, MouseEventHandler, InputHTMLAttributes, TextareaHTMLAttributes, SelectHTMLAttributes, RefObject, KeyboardEvent } from 'react';
3
3
 
4
4
  /**
5
5
  * Join class names, dropping anything falsy.
@@ -67,8 +67,10 @@ declare function Heading({ level, variant, tone, className, ...rest }: HeadingPr
67
67
  interface SpinnerProps extends HTMLAttributes<HTMLSpanElement> {
68
68
  /** Diameter in px. Default 20. */
69
69
  size?: number;
70
- /** Accessible label. Default "Loading". */
71
- label?: string;
70
+ /** Accessible label. Required: the words are the app's, in the app's
71
+ language, and a default here is one no translation file can reach. */
72
+ label: string;
73
+ ref?: Ref<HTMLSpanElement>;
72
74
  }
73
75
  /**
74
76
  * Indeterminate loading ring. Arc takes currentColor, so it matches whatever
@@ -120,15 +122,26 @@ interface IconProps extends HTMLAttributes<HTMLSpanElement> {
120
122
  size?: IconSize;
121
123
  /** Accessible name. Omitted = decorative (aria-hidden). */
122
124
  label?: string;
125
+ ref?: Ref<HTMLSpanElement>;
123
126
  }
124
127
  /** A glyph from the app-registered set, sized on the core scale. */
125
128
  declare function Icon({ name, size, label, className, ...rest }: IconProps): ReactElement;
126
129
 
127
130
  type ButtonVariant = "primary" | "secondary" | "ghost" | "danger" | "warning" | "highlight";
128
131
  type ButtonSize = "sm" | "md" | "lg";
132
+ type ButtonShape = "rect" | "pill";
129
133
  interface ButtonBaseProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "type"> {
130
134
  variant?: ButtonVariant;
131
135
  size?: ButtonSize;
136
+ /** Standing on a picture, where the page's own foreground would be read
137
+ * against a photograph. Only the two see-through variants take it up: a
138
+ * filled button brings its own ground. */
139
+ onMedia?: boolean;
140
+ /** Corner shape, when the default is not the one this button wants: a
141
+ * rectangle where `iconOnly` would round it, or a pill around words.
142
+ * Unset, the shape follows from the size — rect, or a circle when
143
+ * `iconOnly`. */
144
+ shape?: ButtonShape;
132
145
  /** Glyph slots — pass an <Icon> or any node. Agnostic of icon set; the
133
146
  * button sizes the slot from its own size, and publishes that step as
134
147
  * --mds-icon-slot for an icon set that can only size itself. */
@@ -160,9 +173,10 @@ type ButtonProps = ButtonBaseProps & IconOnlyEnforcement;
160
173
  * <Button variant="danger" loading={deleting} onClick={remove}>Delete</Button>
161
174
  * <Button iconOnly aria-label="Close" variant="ghost"><Icon name="close" /></Button>
162
175
  * <Button href="/settings">Settings</Button>
176
+ * <Button iconOnly aria-label="Menu" shape="rect"><Icon name="menu" /></Button>
163
177
  * ```
164
178
  */
165
- declare function Button({ variant, size, iconLeft, iconRight, loading, disabled, fullWidth, iconOnly, type, href, as, className, children, ...rest }: ButtonProps): ReactElement;
179
+ declare function Button({ variant, size, shape, onMedia, iconLeft, iconRight, loading, disabled, fullWidth, iconOnly, type, href, as, className, children, ...rest }: ButtonProps): ReactElement;
166
180
 
167
181
  type LinkVariant = "inline" | "standalone" | "plain";
168
182
  type LinkSize = "xs" | "sm" | "base" | "lg" | "xl";
@@ -180,7 +194,7 @@ type LinkOwnProps<E extends ElementType> = {
180
194
  as?: E;
181
195
  children?: ReactNode;
182
196
  };
183
- type LinkProps<E extends ElementType = "a"> = LinkOwnProps<E> & Omit<ComponentPropsWithoutRef<E>, keyof LinkOwnProps<E>>;
197
+ type LinkProps<E extends ElementType = "a"> = LinkOwnProps<E> & Omit<ComponentPropsWithRef<E>, keyof LinkOwnProps<E>>;
184
198
  /**
185
199
  * Text link. Inline links keep their underline: color alone fails WCAG 1.4.1
186
200
  * for links inside prose.
@@ -208,6 +222,7 @@ interface AvatarProps extends HTMLAttributes<HTMLSpanElement> {
208
222
  /** Hide from assistive tech — for avatars that repeat a name already in
209
223
  the row's text. The name prop still drives the initials. */
210
224
  decorative?: boolean;
225
+ ref?: Ref<HTMLSpanElement>;
211
226
  }
212
227
  /**
213
228
  * Person marker. Image when available, initials otherwise — never an empty circle.
@@ -226,12 +241,17 @@ interface AvatarGroupProps extends HTMLAttributes<HTMLDivElement> {
226
241
  max?: number;
227
242
  /** Sizes the overflow chip to match the avatars. Default "md". */
228
243
  size?: AvatarSize;
244
+ /** Names the "+N" chip, e.g. `(n) => `${n} more``. Required and a function:
245
+ the chip stands for people whose names are not on screen, and only the app
246
+ knows how its language counts them. */
247
+ overflowLabel: (hidden: number) => string;
248
+ ref?: Ref<HTMLDivElement>;
229
249
  }
230
250
  /**
231
251
  * Overlapping stack of avatars with a "+N" chip past `max`.
232
252
  *
233
253
  * ```tsx
234
- * <AvatarGroup max={3}>
254
+ * <AvatarGroup max={3} overflowLabel={(n) => `${n} more`}>
235
255
  * <Avatar name="Ada Lovelace" />
236
256
  * <Avatar name="Grace Hopper" />
237
257
  * <Avatar name="Margaret Hamilton" />
@@ -239,11 +259,12 @@ interface AvatarGroupProps extends HTMLAttributes<HTMLDivElement> {
239
259
  * </AvatarGroup>
240
260
  * ```
241
261
  */
242
- declare function AvatarGroup({ children, max, size, className, ...rest }: AvatarGroupProps): ReactElement;
262
+ declare function AvatarGroup({ children, max, size, overflowLabel, className, ...rest }: AvatarGroupProps): ReactElement;
243
263
 
244
264
  type BadgeTone = "neutral" | "accent" | "danger" | "warning" | "success" | "highlight";
245
265
  interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {
246
266
  tone?: BadgeTone;
267
+ ref?: Ref<HTMLSpanElement>;
247
268
  }
248
269
  /**
249
270
  * Small status marker — counts, "new", state words. Soft fill, strong text.
@@ -268,6 +289,9 @@ interface ChipProps extends HTMLAttributes<HTMLElement> {
268
289
  /** When provided, Chip renders as a `<button>`. */
269
290
  onClick?: MouseEventHandler;
270
291
  disabled?: boolean;
292
+ /** The root is a `<button>` when it has an onClick and a `<span>` otherwise,
293
+ so the ref is typed to what both are. */
294
+ ref?: Ref<HTMLElement>;
271
295
  }
272
296
  /**
273
297
  * Compact pill for filters and single/multi choices. Interactive (a button,
@@ -279,7 +303,7 @@ interface ChipProps extends HTMLAttributes<HTMLElement> {
279
303
  * <Chip variant="outline" icon={<Icon name="pin" />}>Nearby</Chip>
280
304
  * ```
281
305
  */
282
- declare function Chip({ children, variant, selected, icon, onClick, disabled, className, ...rest }: ChipProps): ReactElement;
306
+ declare function Chip({ children, variant, selected, icon, onClick, disabled, className, ref, ...rest }: ChipProps): ReactElement;
283
307
 
284
308
  type ChipGroupGap = "hairline" | "tight" | "base";
285
309
  interface ChipGroupProps extends HTMLAttributes<HTMLDivElement> {
@@ -287,6 +311,7 @@ interface ChipGroupProps extends HTMLAttributes<HTMLDivElement> {
287
311
  children: ReactNode;
288
312
  /** Space between items, on the gap scale. Default "tight". */
289
313
  gap?: ChipGroupGap;
314
+ ref?: Ref<HTMLDivElement>;
290
315
  }
291
316
  /**
292
317
  * Wrapping row of Chips for multi-select choices inside a form (pick several
@@ -315,6 +340,7 @@ interface ChipBarProps extends HTMLAttributes<HTMLDivElement> {
315
340
  bordered?: boolean;
316
341
  /** Fade the trailing edge to hint that the row scrolls. Default true. */
317
342
  fade?: boolean;
343
+ ref?: Ref<HTMLDivElement>;
318
344
  }
319
345
  /**
320
346
  * Horizontally scrollable single-line row of Chips — a filter strip. Items
@@ -356,6 +382,7 @@ interface CountButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>,
356
382
  loading?: boolean;
357
383
  /** Visible text beside the icon — typically a count or a word. */
358
384
  children?: ReactNode;
385
+ ref?: Ref<HTMLButtonElement>;
359
386
  }
360
387
  /**
361
388
  * Inline, chrome-less pressable pairing an icon with a count or word — like,
@@ -394,7 +421,8 @@ interface DateTimePickerProps {
394
421
  value?: string | undefined;
395
422
  /** Fires with the combined ISO string when the user confirms. */
396
423
  onChange: (iso: string) => void;
397
- /** Shown on the trigger when nothing is selected. */
424
+ /** Shown on the trigger when nothing is selected. Nothing is shown without
425
+ it: the component ships no words of its own. */
398
426
  placeholder?: string | undefined;
399
427
  /** Earliest selectable moment as an ISO string. Default: now. */
400
428
  min?: string | undefined;
@@ -407,8 +435,10 @@ interface DateTimePickerProps {
407
435
  "aria-label"?: string | undefined;
408
436
  /** BCP 47 tag for names, week start and hour cycle. Default: runtime locale. */
409
437
  locale?: string | undefined;
410
- /** Overrides for the picker's own strings (defaults are English). */
411
- labels?: Partial<DateTimePickerLabels> | undefined;
438
+ /** Every string the picker says. Required and whole rather than a partial
439
+ over English defaults: a default is a word no translation file reaches,
440
+ and a partial makes the one nobody filled in look deliberate. */
441
+ labels: DateTimePickerLabels;
412
442
  }
413
443
  /**
414
444
  * Mobile-first date + time picker. A trigger styled like Input opens a bottom
@@ -422,6 +452,7 @@ interface DateTimePickerProps {
422
452
  * <DateTimePicker
423
453
  * value={startsAt}
424
454
  * onChange={setStartsAt}
455
+ * labels={t("picker", { returnObjects: true })}
425
456
  * min={new Date().toISOString()}
426
457
  * minuteStep={30}
427
458
  * locale={i18n.language}
@@ -429,27 +460,37 @@ interface DateTimePickerProps {
429
460
  * </Field>
430
461
  * ```
431
462
  */
432
- declare function DateTimePicker({ value, onChange, placeholder, min, minuteStep, disabled, id, "aria-label": ariaLabel, locale, labels, }: DateTimePickerProps): ReactElement;
463
+ declare function DateTimePicker({ value, onChange, placeholder, min, minuteStep, disabled, id, "aria-label": ariaLabel, locale, labels: text, }: DateTimePickerProps): ReactElement;
433
464
 
434
465
  type TagTone = "neutral" | "accent";
435
- interface TagProps extends HTMLAttributes<HTMLSpanElement> {
466
+ type TagProps = HTMLAttributes<HTMLSpanElement> & {
436
467
  children: ReactNode;
437
468
  tone?: TagTone;
438
- /** Renders a labelled ✕ button. Label reads "Remove <content>" when content is text. */
439
- onRemove?: () => void;
440
- }
469
+ ref?: Ref<HTMLSpanElement>;
470
+ } & ({
471
+ /** Renders a ✕ button after the content. */
472
+ onRemove: () => void;
473
+ /** Names that button, e.g. "Remove Beginner". Required alongside
474
+ `onRemove`: the glyph says nothing, and only the app knows how its
475
+ language builds the sentence. */
476
+ removeLabel: string;
477
+ } | {
478
+ onRemove?: undefined;
479
+ removeLabel?: undefined;
480
+ });
441
481
  /**
442
482
  * Content label chip — categories, filters, topics.
443
483
  *
444
484
  * ```tsx
445
485
  * <Tag>Design</Tag>
446
- * <Tag tone="accent" onRemove={() => remove(id)}>Beginner</Tag>
486
+ * <Tag tone="accent" onRemove={() => remove(id)} removeLabel="Remove Beginner">Beginner</Tag>
447
487
  * ```
448
488
  */
449
- declare function Tag({ children, tone, onRemove, className, ...rest }: TagProps): ReactElement;
489
+ declare function Tag({ children, tone, onRemove, removeLabel, className, ...rest }: TagProps): ReactElement;
450
490
 
451
491
  interface DividerProps extends HTMLAttributes<HTMLDivElement> {
452
492
  orientation?: "horizontal" | "vertical";
493
+ ref?: Ref<HTMLDivElement>;
453
494
  }
454
495
  /**
455
496
  * Visual separator. Semantic separator role via <hr>-equivalent div.
@@ -461,12 +502,33 @@ interface DividerProps extends HTMLAttributes<HTMLDivElement> {
461
502
  */
462
503
  declare function Divider({ orientation, className, ...rest }: DividerProps): ReactElement;
463
504
 
505
+ interface VisuallyHiddenProps extends HTMLAttributes<HTMLElement> {
506
+ /** Element override when the markup needs a particular tag — a page's h1, a
507
+ table's thead. Default "span". */
508
+ as?: keyof JSX.IntrinsicElements;
509
+ }
510
+ /**
511
+ * Text for screen readers and not for eyes.
512
+ *
513
+ * The design does not always draw what the markup owes: a screen whose title is
514
+ * the tab bar underneath it still needs an h1, and a table whose columns are
515
+ * obvious to look at still needs a thead. Both go here rather than into a
516
+ * one-off class in the app.
517
+ *
518
+ * ```tsx
519
+ * <VisuallyHidden as="h1">Discover</VisuallyHidden>
520
+ * <VisuallyHidden role="status" aria-live="polite">{message}</VisuallyHidden>
521
+ * ```
522
+ */
523
+ declare function VisuallyHidden({ as, className, ...rest }: VisuallyHiddenProps): ReactElement;
524
+
464
525
  type SkeletonVariant = "text" | "rect" | "circle";
465
526
  interface SkeletonProps extends HTMLAttributes<HTMLSpanElement> {
466
527
  variant?: SkeletonVariant;
467
528
  /** Any CSS length. Text defaults to full width, one line tall. */
468
529
  width?: string;
469
530
  height?: string;
531
+ ref?: Ref<HTMLSpanElement>;
470
532
  }
471
533
  /**
472
534
  * Loading placeholder. aria-hidden — the loading announcement belongs to the
@@ -493,7 +555,11 @@ interface ProgressBarProps extends HTMLAttributes<HTMLDivElement> {
493
555
  value?: number;
494
556
  /** Accessible name — required. A bare bar announces nothing useful. */
495
557
  label: string;
558
+ /** What the bar has got through, in words — "2.1 MB of 5 MB". Read instead
559
+ of the percentage, which is not always what the number means. */
560
+ valueText?: string;
496
561
  indeterminate?: boolean;
562
+ ref?: Ref<HTMLDivElement>;
497
563
  }
498
564
  /**
499
565
  * Determinate or indeterminate progress track.
@@ -503,7 +569,7 @@ interface ProgressBarProps extends HTMLAttributes<HTMLDivElement> {
503
569
  * <ProgressBar label="Syncing" indeterminate />
504
570
  * ```
505
571
  */
506
- declare function ProgressBar({ value, label, indeterminate, className, style, ...rest }: ProgressBarProps): ReactElement;
572
+ declare function ProgressBar({ value, label, valueText, indeterminate, className, style, ...rest }: ProgressBarProps): ReactElement;
507
573
 
508
574
  interface FieldContextValue {
509
575
  /** Control id — the label points here. */
@@ -563,18 +629,25 @@ interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size">
563
629
  */
564
630
  declare function Input({ size, invalid, iconLeft, iconRight, className, ...rest }: InputProps): ReactElement;
565
631
 
566
- type PasswordInputProps = Omit<InputProps, "type">;
632
+ interface PasswordInputProps extends Omit<InputProps, "type"> {
633
+ /** Names the reveal button while the password is hidden, e.g. "Show password".
634
+ Required: the button carries no visible text, so this is the only thing a
635
+ screen reader has, and it is the app's language rather than the system's. */
636
+ showLabel: string;
637
+ /** Names the same button while the password is visible, e.g. "Hide password". */
638
+ hideLabel: string;
639
+ }
567
640
  /**
568
641
  * Password field with a reveal toggle. Composes Input, so inside a Field it
569
642
  * inherits id/description/invalid the same way.
570
643
  *
571
644
  * ```tsx
572
645
  * <Field label="Password" hint="At least 12 characters">
573
- * <PasswordInput autoComplete="new-password" />
646
+ * <PasswordInput showLabel="Show password" hideLabel="Hide password" autoComplete="new-password" />
574
647
  * </Field>
575
648
  * ```
576
649
  */
577
- declare function PasswordInput({ className, ...rest }: PasswordInputProps): ReactElement;
650
+ declare function PasswordInput({ showLabel, hideLabel, className, ...rest }: PasswordInputProps): ReactElement;
578
651
 
579
652
  interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
580
653
  /** Character counter under the control; pairs with native maxLength. */
@@ -718,6 +791,9 @@ declare function SegmentedControl<T extends string = string>({ label, options, v
718
791
  interface SearchFieldProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "size" | "value" | "onChange"> {
719
792
  /** Accessible name. */
720
793
  label: string;
794
+ /** Names the clear button, e.g. "Clear search". Required: the button is a
795
+ glyph, so this is all a screen reader has, and the words are the app's. */
796
+ clearLabel: string;
721
797
  value: string;
722
798
  /** Receives the new text — "" when cleared. */
723
799
  onChange: (value: string) => void;
@@ -727,15 +803,16 @@ interface SearchFieldProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "
727
803
  * Controlled search input with a clear affordance once there is text.
728
804
  *
729
805
  * ```tsx
730
- * <SearchField label="Search sessions" value={query} onChange={setQuery} />
806
+ * <SearchField label="Search sessions" clearLabel="Clear search" value={query} onChange={setQuery} />
731
807
  * ```
732
808
  */
733
- declare function SearchField({ label, value, onChange, className, ...rest }: SearchFieldProps): ReactElement;
809
+ declare function SearchField({ label, clearLabel, value, onChange, className, ...rest }: SearchFieldProps): ReactElement;
734
810
 
735
811
  interface ListGroupProps extends HTMLAttributes<HTMLUListElement> {
736
812
  children: ReactNode;
737
813
  /** Heading over the group. Also names the list to a screen reader. */
738
814
  label?: ReactNode;
815
+ ref?: Ref<HTMLUListElement>;
739
816
  }
740
817
  /**
741
818
  * Card-styled list container for ListItems.
@@ -769,6 +846,8 @@ interface ListItemProps extends Omit<HTMLAttributes<HTMLElement>, "title" | "onC
769
846
  pressed?: boolean;
770
847
  /** Makes the whole row a link. Wins over onClick. */
771
848
  href?: string;
849
+ /** Element override for that link, e.g. a router's Link. */
850
+ as?: ElementType;
772
851
  /** What the row paints behind itself. Inside a ListGroup the group is the
773
852
  card, so grouped rows default to painting nothing; standalone rows
774
853
  default to their own card. `accent` is the tinted, accent-edged prompt
@@ -776,12 +855,15 @@ interface ListItemProps extends Omit<HTMLAttributes<HTMLElement>, "title" | "onC
776
855
  brings its own corner radius, which peeks past the row's in all four
777
856
  corners. */
778
857
  surface?: ListItemSurface;
858
+ /** The root is an `<li>` inside a ListGroup and a `<div>` outside one, so
859
+ the ref is typed to what both are. */
860
+ ref?: Ref<HTMLElement>;
779
861
  }
780
862
  /**
781
863
  * One row. Static by default; interactive as one whole-row button/link.
782
864
  * An `<li>` inside a ListGroup, a standalone `<div>` row anywhere else.
783
865
  */
784
- declare function ListItem({ title, description, leading, trailing, onClick, pressed, href, surface, className, ...rest }: ListItemProps): ReactElement;
866
+ declare function ListItem({ title, description, leading, trailing, onClick, pressed, href, as, surface, className, ref, ...rest }: ListItemProps): ReactElement;
785
867
 
786
868
  interface EmptyStateProps {
787
869
  title: string;
@@ -830,16 +912,19 @@ interface TabListProps extends HTMLAttributes<HTMLDivElement> {
830
912
  /** Accessible name for the tab set. */
831
913
  label: string;
832
914
  children: ReactNode;
915
+ ref?: Ref<HTMLDivElement>;
833
916
  }
834
917
  declare function TabList({ label, className, children, ...rest }: TabListProps): ReactElement;
835
918
  interface TabProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "value" | "type"> {
836
919
  value: string;
837
920
  children: ReactNode;
921
+ ref?: Ref<HTMLButtonElement>;
838
922
  }
839
923
  declare function Tab({ value, className, children, ...rest }: TabProps): ReactElement;
840
924
  interface TabPanelProps extends HTMLAttributes<HTMLDivElement> {
841
925
  value: string;
842
926
  children: ReactNode;
927
+ ref?: Ref<HTMLDivElement>;
843
928
  }
844
929
  declare function TabPanel({ value, className, children, ...rest }: TabPanelProps): ReactElement;
845
930
 
@@ -858,19 +943,19 @@ interface ToastContextValue {
858
943
  declare function useToast(): ToastContextValue;
859
944
  interface ToastProviderProps {
860
945
  children: ReactNode;
861
- /** Accessible name of the notification region (localise). Default "Notifications". */
862
- regionLabel?: string | undefined;
863
- /** Prefix of each dismiss button's accessible name (localise). The toast's
864
- * title follows it, so every dismiss control names its own toast. Default
865
- * "Dismiss" — a button labelled "Dismiss: Saved". */
866
- dismissLabel?: string | undefined;
946
+ /** Accessible name of the notification region, e.g. "Notifications".
947
+ Required: it is read aloud, in the app's language. */
948
+ regionLabel: string;
949
+ /** Prefix of each dismiss button's accessible name. The toast's title follows
950
+ * it, so every dismiss control names its own toast: "Dismiss: Saved". */
951
+ dismissLabel: string;
867
952
  }
868
953
  /**
869
954
  * Mount once near the root. Renders the notification region itself.
870
955
  *
871
956
  * ```tsx
872
957
  * // App root
873
- * <ToastProvider>
958
+ * <ToastProvider regionLabel="Notifications" dismissLabel="Dismiss">
874
959
  * <App />
875
960
  * </ToastProvider>
876
961
  *
@@ -963,6 +1048,11 @@ interface CardProps extends Omit<HTMLAttributes<HTMLElement>, "onClick"> {
963
1048
  onClick?: () => void;
964
1049
  /** Makes the whole card a link. Wins over onClick. */
965
1050
  href?: string;
1051
+ /** Element override for that link, e.g. a router's Link. */
1052
+ as?: ElementType;
1053
+ /** The root is an `<a>`, a `<button>` or a `<div>` depending on the props,
1054
+ so the ref is typed to what all three are. */
1055
+ ref?: Ref<HTMLElement>;
966
1056
  }
967
1057
  /**
968
1058
  * Surface container. Compose with CardHeader/CardBody/CardFooter — the card
@@ -978,8 +1068,10 @@ interface CardProps extends Omit<HTMLAttributes<HTMLElement>, "onClick"> {
978
1068
  * <Card href="/items/42" variant="flat">…</Card>
979
1069
  * ```
980
1070
  */
981
- declare function Card({ children, variant, emphasis, onClick, href, className, ...rest }: CardProps): ReactElement;
982
- type CardSectionProps = HTMLAttributes<HTMLDivElement>;
1071
+ declare function Card({ children, variant, emphasis, onClick, href, as, className, ref, ...rest }: CardProps): ReactElement;
1072
+ type CardSectionProps = HTMLAttributes<HTMLDivElement> & {
1073
+ ref?: Ref<HTMLDivElement>;
1074
+ };
983
1075
  /** Top slot — title row, media, tabs. */
984
1076
  declare function CardHeader({ className, ...rest }: CardSectionProps): ReactElement;
985
1077
  /** Main content slot. */
@@ -1084,8 +1176,9 @@ interface ConfirmDialogProps<T = void> {
1084
1176
  /** Consequence explained in a sentence or two. */
1085
1177
  description?: ReactNode;
1086
1178
  confirmLabel: string;
1087
- /** @default "Cancel" */
1088
- cancelLabel?: string;
1179
+ /** Names the way out, e.g. "Cancel". Required: it is a button with words on
1180
+ it, and the words are the app's. */
1181
+ cancelLabel: string;
1089
1182
  /** Styles the confirm action: danger for destructive, warning for
1090
1183
  consequential-but-recoverable. */
1091
1184
  tone?: ConfirmDialogTone;
@@ -1111,6 +1204,7 @@ interface ConfirmDialogProps<T = void> {
1111
1204
  * title="Delete session?"
1112
1205
  * description="This cannot be undone."
1113
1206
  * confirmLabel="Delete"
1207
+ * cancelLabel="Cancel"
1114
1208
  * tone="danger"
1115
1209
  * />
1116
1210
  * ```
@@ -1205,8 +1299,11 @@ interface TabBarItemProps {
1205
1299
  /** Attention dot on the icon — unread, pending. Boolean only: the count
1206
1300
  lives on the destination screen, the bar just says "something's there". */
1207
1301
  badge?: boolean | undefined;
1302
+ /** Element override for the link, e.g. a router's Link. A bottom bar is
1303
+ where a full page reload costs the most — it restarts the whole shell. */
1304
+ as?: ElementType;
1208
1305
  }
1209
- declare function TabBarItem({ label, icon, href, onClick, active, badge }: TabBarItemProps): react.JSX.Element;
1306
+ declare function TabBarItem({ label, icon, href, onClick, active, badge, as }: TabBarItemProps): react.JSX.Element;
1210
1307
  interface TabBarActionProps {
1211
1308
  /** Names the action — icon-only, so this is all a screen reader gets. */
1212
1309
  label: string;
@@ -1217,6 +1314,289 @@ interface TabBarActionProps {
1217
1314
  it is a peer child, and the bar's flex layout leaves it its own width. */
1218
1315
  declare function TabBarAction({ label, icon, onClick }: TabBarActionProps): react.JSX.Element;
1219
1316
 
1317
+ interface MediaPlaceholderProps extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
1318
+ /** CSS aspect-ratio for the box, e.g. "4 / 5". Default 16 / 9. */
1319
+ aspect?: string;
1320
+ /** Picture to draw. Absent, or broken, leaves the empty surface showing. */
1321
+ src?: string;
1322
+ /** Describes the picture. Empty = decorative, which is the honest default:
1323
+ a file name is not a description. */
1324
+ alt?: string;
1325
+ /** Glyph for the empty surface — an <Icon> or any node. */
1326
+ glyph?: ReactNode;
1327
+ /** A few words under the glyph, or over the picture. */
1328
+ caption?: string;
1329
+ /** Obscures the media without hiding that there is media. */
1330
+ blurred?: boolean;
1331
+ /** Drawn over the surface, outside the blur — a reveal prompt, a badge, a
1332
+ play button. The consent vocabulary that usually goes here belongs to the
1333
+ app, so the system takes it as a node and asks no questions about it. */
1334
+ cover?: ReactNode;
1335
+ ref?: Ref<HTMLDivElement>;
1336
+ }
1337
+ /**
1338
+ * The box a picture goes in, whether or not there is one yet.
1339
+ *
1340
+ * ```tsx
1341
+ * <MediaPlaceholder
1342
+ * aspect="4 / 5"
1343
+ * src={post.media.src}
1344
+ * alt={post.media.alt}
1345
+ * blurred={!revealed}
1346
+ * cover={post.sensitive && <SensitiveMediaOverlay onReveal={reveal} />}
1347
+ * />
1348
+ * ```
1349
+ */
1350
+ declare function MediaPlaceholder({ aspect, src, alt, glyph, caption, blurred, cover, className, style, ...rest }: MediaPlaceholderProps): ReactElement;
1351
+
1352
+ interface CarouselSlide {
1353
+ id: string;
1354
+ src?: string;
1355
+ alt?: string;
1356
+ /** CSS aspect-ratio for this frame. Default 4 / 3. */
1357
+ aspect?: string;
1358
+ caption?: string;
1359
+ /** Obscures the frame and takes away the way into it: a covered frame does
1360
+ not open larger, however it is tapped. */
1361
+ covered?: boolean;
1362
+ /** Drawn over the frame, outside the blur — whatever the app asks consent
1363
+ with. */
1364
+ cover?: ReactNode;
1365
+ }
1366
+ type CarouselPager = "thumbnails" | "dots" | "none";
1367
+ interface ImageCarouselLabels {
1368
+ /** Names the carousel landmark, e.g. "Images". */
1369
+ region: string;
1370
+ /** Read out in place of "region", e.g. "carousel". A screen reader says it
1371
+ aloud, so it is the app's word in the app's language. */
1372
+ carouselRole: string;
1373
+ /** The same for one frame, e.g. "slide". */
1374
+ slideRole: string;
1375
+ previous: string;
1376
+ next: string;
1377
+ /** "3 of 8" — a function, because only the app knows how its language counts. */
1378
+ counter: (current: number, total: number) => string;
1379
+ /** Names one frame's thumbnail or dot, e.g. "Image 3". */
1380
+ slide: (position: number) => string;
1381
+ /** Names the button standing for the frames no thumbnail fits. */
1382
+ more: (hidden: number) => string;
1383
+ }
1384
+ type ImageCarouselProps = Omit<HTMLAttributes<HTMLElement>, "children" | "onChange"> & {
1385
+ slides: CarouselSlide[];
1386
+ labels: ImageCarouselLabels;
1387
+ /** Held index. Unset, the carousel keeps its own. */
1388
+ index?: number;
1389
+ defaultIndex?: number;
1390
+ onIndexChange?: (index: number) => void;
1391
+ pager?: CarouselPager;
1392
+ maxThumbnails?: number;
1393
+ ref?: Ref<HTMLElement>;
1394
+ } & ({
1395
+ /** Called with the frame to open larger — by the control, or by a tap
1396
+ on the frame itself. */
1397
+ onZoom: (index: number) => void;
1398
+ /** Glyph for that control, from the app's icon set. */
1399
+ zoomIcon: ReactNode;
1400
+ zoomLabel: string;
1401
+ } | {
1402
+ onZoom?: undefined;
1403
+ zoomIcon?: undefined;
1404
+ zoomLabel?: undefined;
1405
+ });
1406
+ /**
1407
+ * A gallery of frames, one on show.
1408
+ *
1409
+ * ```tsx
1410
+ * <ImageCarousel
1411
+ * slides={post.images.map((image) => ({ ...image, covered: !revealed }))}
1412
+ * labels={t.gallery}
1413
+ * onZoom={openLightbox}
1414
+ * zoomIcon={<Icon name="zoom-in" />}
1415
+ * zoomLabel={t.viewLarger}
1416
+ * />
1417
+ * ```
1418
+ */
1419
+ declare function ImageCarousel({ slides, labels, index, defaultIndex, onIndexChange, pager, maxThumbnails, onZoom, zoomIcon, zoomLabel, className, ...rest }: ImageCarouselProps): ReactElement | null;
1420
+
1421
+ type UploadStatus = "uploading" | "processing" | "done" | "error";
1422
+ interface UploadProgressLabels {
1423
+ /** Names the bar while bytes are moving, and the state after. */
1424
+ uploading: string;
1425
+ processing: string;
1426
+ done: string;
1427
+ /** Shown when the caller has no more specific `error` to give. */
1428
+ error: string;
1429
+ cancel: string;
1430
+ retry: string;
1431
+ remove: string;
1432
+ }
1433
+ interface UploadProgressProps extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
1434
+ /** The file, as the person who picked it would name it. */
1435
+ name: string;
1436
+ labels: UploadProgressLabels;
1437
+ /** Thumbnail of what is going up — an `<img>`, a `<video>`, anything. */
1438
+ preview?: ReactNode;
1439
+ /** Glyph for the state it ended in, from the app's icon set. Tinted by the
1440
+ status: the system says which state, the app says with what glyph. */
1441
+ mark?: ReactNode;
1442
+ /** 0–100. Ignored while processing, which reports no percentage. */
1443
+ value?: number;
1444
+ status?: UploadStatus;
1445
+ /** The progress in words — "2.1 MB of 5 MB". Read out instead of the
1446
+ percentage, and shown under the bar. */
1447
+ detail?: string;
1448
+ /** Why it failed. Falls back to `labels.error`. */
1449
+ error?: string;
1450
+ onCancel?: () => void;
1451
+ onRetry?: () => void;
1452
+ onRemove?: () => void;
1453
+ ref?: Ref<HTMLDivElement>;
1454
+ }
1455
+ /**
1456
+ * One file on its way up: what it is, how far it has got, and the way out.
1457
+ *
1458
+ * ```tsx
1459
+ * <UploadProgress
1460
+ * name={file.name}
1461
+ * status={upload.status}
1462
+ * value={upload.percent}
1463
+ * detail={`${sent} of ${total}`}
1464
+ * onCancel={upload.abort}
1465
+ * labels={t.upload}
1466
+ * />
1467
+ * ```
1468
+ */
1469
+ declare function UploadProgress({ name, labels, preview, mark, value, status, detail, error, onCancel, onRetry, onRemove, className, ...rest }: UploadProgressProps): ReactElement;
1470
+
1471
+ interface LightboxLabels {
1472
+ /** Names the dialog itself, e.g. "Image". */
1473
+ dialog: string;
1474
+ close: string;
1475
+ zoomIn: string;
1476
+ zoomOut: string;
1477
+ }
1478
+ interface LightboxProps {
1479
+ open: boolean;
1480
+ onClose: () => void;
1481
+ src: string;
1482
+ /** Empty says the picture is decoration — rare here, where it is the point. */
1483
+ alt?: string;
1484
+ caption?: string;
1485
+ labels: LightboxLabels;
1486
+ }
1487
+ /**
1488
+ * One picture, full screen, zoomable and pannable. Escape and the focus trap
1489
+ * come from the overlay shell; the gestures are the component's own.
1490
+ *
1491
+ * ```tsx
1492
+ * <Lightbox
1493
+ * open={shown !== null}
1494
+ * onClose={() => setShown(null)}
1495
+ * src={shown?.src ?? ""}
1496
+ * alt={shown?.alt ?? ""}
1497
+ * labels={{ dialog: t("image"), close: t("close"), zoomIn: t("zoomIn"), zoomOut: t("zoomOut") }}
1498
+ * />
1499
+ * ```
1500
+ */
1501
+ declare function Lightbox({ open, onClose, src, alt, caption, labels }: LightboxProps): react.JSX.Element;
1502
+
1503
+ interface VideoChapter {
1504
+ /** Where the chapter starts, in seconds. */
1505
+ at: number;
1506
+ label: string;
1507
+ }
1508
+ interface VideoCaptions {
1509
+ src: string;
1510
+ lang: string;
1511
+ /** Shown in the browser's own track menu, so it is the app's word. */
1512
+ label: string;
1513
+ defaultOn?: boolean;
1514
+ }
1515
+ interface VideoPlayerLabels {
1516
+ /** Names the player itself, e.g. "Hip harness, slowly". */
1517
+ region: string;
1518
+ play: string;
1519
+ pause: string;
1520
+ mute: string;
1521
+ unmute: string;
1522
+ fullscreen: string;
1523
+ exitFullscreen: string;
1524
+ seek: string;
1525
+ }
1526
+ type Chaptered = {
1527
+ chapters: VideoChapter[];
1528
+ chaptersLabel: string;
1529
+ onChapterSelect?: (at: number) => void;
1530
+ } | {
1531
+ chapters?: undefined;
1532
+ chaptersLabel?: undefined;
1533
+ onChapterSelect?: undefined;
1534
+ };
1535
+ type Captioned = {
1536
+ captions: VideoCaptions;
1537
+ captionsLabel: string;
1538
+ } | {
1539
+ captions?: undefined;
1540
+ captionsLabel?: undefined;
1541
+ };
1542
+ type VideoPlayerProps = Omit<HTMLAttributes<HTMLElement>, "children"> & {
1543
+ src: string;
1544
+ poster?: string;
1545
+ labels: VideoPlayerLabels;
1546
+ autoPlay?: boolean;
1547
+ /** Obscures the picture and takes away the way into it — the cover is the
1548
+ only way in while this is set. */
1549
+ covered?: boolean;
1550
+ /** Drawn over the picture, outside the blur: whatever asks to be let past. */
1551
+ cover?: ReactNode;
1552
+ ref?: Ref<HTMLElement>;
1553
+ } & Chaptered & Captioned;
1554
+ /**
1555
+ * A video with its own transport: play, seek, sound, captions, fullscreen and
1556
+ * chapters. The picture can be covered — `covered` obscures it and `cover`
1557
+ * holds whatever asks to be let past, which is the app's to write.
1558
+ *
1559
+ * ```tsx
1560
+ * <VideoPlayer
1561
+ * src={video.url}
1562
+ * poster={video.posterUrl}
1563
+ * labels={{ region: t("video.of", { title }), play: t("video.play"), … }}
1564
+ * chapters={chapters}
1565
+ * chaptersLabel={t("video.chapters")}
1566
+ * />
1567
+ * ```
1568
+ */
1569
+ declare function VideoPlayer({ src, poster, labels, chapters, chaptersLabel, onChapterSelect, captions, captionsLabel, autoPlay, covered, cover, className, ref, ...rest }: VideoPlayerProps): ReactElement;
1570
+
1571
+ interface Crumb {
1572
+ label: string;
1573
+ /** Absent = not a link. The last step never links, wherever it points. */
1574
+ href?: string;
1575
+ }
1576
+ interface BreadcrumbProps extends Omit<HTMLAttributes<HTMLElement>, "children"> {
1577
+ /** The trail, root first. The last item is where the reader is. */
1578
+ items: Crumb[];
1579
+ /** Names the landmark, e.g. "Breadcrumb". Required: a page can hold several
1580
+ navigation landmarks, and the words are the app's. */
1581
+ label: string;
1582
+ /** Element the links render as, e.g. a router's Link. */
1583
+ linkAs?: ElementType;
1584
+ ref?: Ref<HTMLElement>;
1585
+ }
1586
+ /**
1587
+ * The trail back up. A navigation landmark holding an ordered list, with the
1588
+ * current page as its last, unlinked step.
1589
+ *
1590
+ * ```tsx
1591
+ * <Breadcrumb
1592
+ * label={t("nav.breadcrumb")}
1593
+ * linkAs={RouterLink}
1594
+ * items={[{ label: "Library", href: "/library" }, { label: "Kihon" }]}
1595
+ * />
1596
+ * ```
1597
+ */
1598
+ declare function Breadcrumb({ items, label, linkAs, className, ...rest }: BreadcrumbProps): ReactElement | null;
1599
+
1220
1600
  interface UseOverlayOptions {
1221
1601
  open: boolean;
1222
1602
  onClose: () => void;
@@ -1297,4 +1677,4 @@ interface RovingGroupOptions {
1297
1677
  */
1298
1678
  declare function useRovingGroup(ref: RefObject<HTMLElement | null>, { selector, orientation }: RovingGroupOptions): (event: KeyboardEvent<HTMLElement>) => void;
1299
1679
 
1300
- export { AppBar, type AppBarProps, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, type AvatarSize, Badge, type BadgeProps, type BadgeTone, Button, type ButtonProps, type ButtonSize, type ButtonVariant, type CSSVars, Card, CardBody, CardFooter, CardHeader, type CardProps, type CardSectionProps, type CardVariant, Checkbox, type CheckboxProps, Chip, ChipBar, type ChipBarGap, type ChipBarProps, ChipGroup, type ChipGroupGap, type ChipGroupProps, type ChipProps, type ChipVariant, ConfirmDialog, type ConfirmDialogProps, type ConfirmDialogTone, Container, type ContainerProps, type ContainerWidth, CountButton, type CountButtonProps, type CountButtonTone, DateTimePicker, type DateTimePickerLabels, type DateTimePickerProps, Divider, type DividerProps, EmptyState, type EmptyStateProps, Field, type FieldContextValue, type FieldProps, Heading, type HeadingLevel, type HeadingProps, type HeadingTone, Icon, type IconProps, IconProvider, type IconProviderProps, type IconRender, type IconRenderProps, type IconSize, Inline, type InlineAlign, type InlineGap, type InlineJustify, type InlineProps, Input, type InputProps, type InputSize, Link, type LinkProps, type LinkVariant, ListGroup, type ListGroupProps, ListItem, type ListItemProps, Modal, ModalBody, ModalFooter, ModalHeader, type ModalProps, type OverlayHistory, OverlayHistoryContext, PasswordInput, type PasswordInputProps, type Presence, ProgressBar, type ProgressBarProps, Radio, type RadioProps, type RovingGroupOptions, Screen, ScreenContent, type ScreenContentProps, SearchField, type SearchFieldProps, type SegmentOption, SegmentedControl, type SegmentedControlProps, Select, type SelectProps, type SelectSize, Sheet, SheetBody, SheetFooter, SheetHeader, type SheetProps, Skeleton, type SkeletonProps, type SkeletonVariant, Spinner, type SpinnerProps, Stack, type StackAlign, type StackGap, type StackProps, Switch, type SwitchProps, Tab, TabBar, TabBarAction, type TabBarActionProps, TabBarItem, type TabBarItemProps, type TabBarProps, TabList, type TabListProps, TabPanel, type TabPanelProps, type TabProps, Tabs, type TabsProps, Tag, type TagProps, type TagTone, Text, type TextProps, type TextTone, type TextVariant, Textarea, type TextareaProps, type ToastOptions, ToastProvider, type ToastProviderProps, type ToastTone, type UseOverlayOptions, cx, useFieldContext, useOverlay, usePresence, useRovingGroup, useToast };
1680
+ export { AppBar, type AppBarProps, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, type AvatarSize, Badge, type BadgeProps, type BadgeTone, Breadcrumb, type BreadcrumbProps, Button, type ButtonProps, type ButtonShape, type ButtonSize, type ButtonVariant, type CSSVars, Card, CardBody, CardFooter, CardHeader, type CardProps, type CardSectionProps, type CardVariant, type CarouselPager, type CarouselSlide, Checkbox, type CheckboxProps, Chip, ChipBar, type ChipBarGap, type ChipBarProps, ChipGroup, type ChipGroupGap, type ChipGroupProps, type ChipProps, type ChipVariant, ConfirmDialog, type ConfirmDialogProps, type ConfirmDialogTone, Container, type ContainerProps, type ContainerWidth, CountButton, type CountButtonProps, type CountButtonTone, type Crumb, DateTimePicker, type DateTimePickerLabels, type DateTimePickerProps, Divider, type DividerProps, EmptyState, type EmptyStateProps, Field, type FieldContextValue, type FieldProps, Heading, type HeadingLevel, type HeadingProps, type HeadingTone, Icon, type IconProps, IconProvider, type IconProviderProps, type IconRender, type IconRenderProps, type IconSize, ImageCarousel, type ImageCarouselLabels, type ImageCarouselProps, Inline, type InlineAlign, type InlineGap, type InlineJustify, type InlineProps, Input, type InputProps, type InputSize, Lightbox, type LightboxLabels, type LightboxProps, Link, type LinkProps, type LinkVariant, ListGroup, type ListGroupProps, ListItem, type ListItemProps, MediaPlaceholder, type MediaPlaceholderProps, Modal, ModalBody, ModalFooter, ModalHeader, type ModalProps, type OverlayHistory, OverlayHistoryContext, PasswordInput, type PasswordInputProps, type Presence, ProgressBar, type ProgressBarProps, Radio, type RadioProps, type RovingGroupOptions, Screen, ScreenContent, type ScreenContentProps, SearchField, type SearchFieldProps, type SegmentOption, SegmentedControl, type SegmentedControlProps, Select, type SelectProps, type SelectSize, Sheet, SheetBody, SheetFooter, SheetHeader, type SheetProps, Skeleton, type SkeletonProps, type SkeletonVariant, Spinner, type SpinnerProps, Stack, type StackAlign, type StackGap, type StackProps, Switch, type SwitchProps, Tab, TabBar, TabBarAction, type TabBarActionProps, TabBarItem, type TabBarItemProps, type TabBarProps, TabList, type TabListProps, TabPanel, type TabPanelProps, type TabProps, Tabs, type TabsProps, Tag, type TagProps, type TagTone, Text, type TextProps, type TextTone, type TextVariant, Textarea, type TextareaProps, type ToastOptions, ToastProvider, type ToastProviderProps, type ToastTone, UploadProgress, type UploadProgressLabels, type UploadProgressProps, type UploadStatus, type UseOverlayOptions, type VideoCaptions, type VideoChapter, VideoPlayer, type VideoPlayerLabels, type VideoPlayerProps, VisuallyHidden, type VisuallyHiddenProps, cx, useFieldContext, useOverlay, usePresence, useRovingGroup, useToast };