@twentyfirstmedia/ui-core 0.2.0 → 0.3.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.
Files changed (146) hide show
  1. package/dist/components/admin.d.ts.map +1 -1
  2. package/dist/components/admin.js +95 -71
  3. package/dist/components/admin.js.map +1 -1
  4. package/dist/components/agents.d.ts.map +1 -1
  5. package/dist/components/agents.js +49 -35
  6. package/dist/components/agents.js.map +1 -1
  7. package/dist/components/app-chrome.d.ts.map +1 -1
  8. package/dist/components/app-chrome.js +6 -2
  9. package/dist/components/app-chrome.js.map +1 -1
  10. package/dist/components/approvals.d.ts.map +1 -1
  11. package/dist/components/approvals.js +22 -18
  12. package/dist/components/approvals.js.map +1 -1
  13. package/dist/components/building-blocks.d.ts.map +1 -1
  14. package/dist/components/building-blocks.js +6 -2
  15. package/dist/components/building-blocks.js.map +1 -1
  16. package/dist/components/charts.d.ts.map +1 -1
  17. package/dist/components/charts.js +20 -10
  18. package/dist/components/charts.js.map +1 -1
  19. package/dist/components/chat.d.ts.map +1 -1
  20. package/dist/components/chat.js +31 -19
  21. package/dist/components/chat.js.map +1 -1
  22. package/dist/components/commerce.d.ts +2 -2
  23. package/dist/components/commerce.d.ts.map +1 -1
  24. package/dist/components/commerce.js +45 -31
  25. package/dist/components/commerce.js.map +1 -1
  26. package/dist/components/data-display.d.ts +5 -9
  27. package/dist/components/data-display.d.ts.map +1 -1
  28. package/dist/components/data-display.js +34 -35
  29. package/dist/components/data-display.js.map +1 -1
  30. package/dist/components/data-table.d.ts.map +1 -1
  31. package/dist/components/data-table.js +15 -10
  32. package/dist/components/data-table.js.map +1 -1
  33. package/dist/components/developer.d.ts.map +1 -1
  34. package/dist/components/developer.js +20 -11
  35. package/dist/components/developer.js.map +1 -1
  36. package/dist/components/feedback.d.ts.map +1 -1
  37. package/dist/components/feedback.js +12 -6
  38. package/dist/components/feedback.js.map +1 -1
  39. package/dist/components/form.d.ts +2 -1
  40. package/dist/components/form.d.ts.map +1 -1
  41. package/dist/components/form.js +12 -9
  42. package/dist/components/form.js.map +1 -1
  43. package/dist/components/forms.d.ts +2 -1
  44. package/dist/components/forms.d.ts.map +1 -1
  45. package/dist/components/forms.js +92 -42
  46. package/dist/components/forms.js.map +1 -1
  47. package/dist/components/foundation.d.ts +5 -2
  48. package/dist/components/foundation.d.ts.map +1 -1
  49. package/dist/components/foundation.js +15 -12
  50. package/dist/components/foundation.js.map +1 -1
  51. package/dist/components/inputs.d.ts.map +1 -1
  52. package/dist/components/inputs.js +3 -1
  53. package/dist/components/inputs.js.map +1 -1
  54. package/dist/components/mail.d.ts.map +1 -1
  55. package/dist/components/mail.js +15 -10
  56. package/dist/components/mail.js.map +1 -1
  57. package/dist/components/media.d.ts.map +1 -1
  58. package/dist/components/media.js +39 -18
  59. package/dist/components/media.js.map +1 -1
  60. package/dist/components/navigation.d.ts.map +1 -1
  61. package/dist/components/navigation.js +21 -9
  62. package/dist/components/navigation.js.map +1 -1
  63. package/dist/components/operations.d.ts.map +1 -1
  64. package/dist/components/operations.js +37 -27
  65. package/dist/components/operations.js.map +1 -1
  66. package/dist/components/previews.d.ts.map +1 -1
  67. package/dist/components/previews.js +14 -10
  68. package/dist/components/previews.js.map +1 -1
  69. package/dist/components/primitives.d.ts.map +1 -1
  70. package/dist/components/primitives.js +4 -1
  71. package/dist/components/primitives.js.map +1 -1
  72. package/dist/components/real-estate.d.ts.map +1 -1
  73. package/dist/components/real-estate.js +43 -28
  74. package/dist/components/real-estate.js.map +1 -1
  75. package/dist/components/rich-text-editor.d.ts.map +1 -1
  76. package/dist/components/rich-text-editor.js +18 -15
  77. package/dist/components/rich-text-editor.js.map +1 -1
  78. package/dist/components/select-menu.d.ts.map +1 -1
  79. package/dist/components/select-menu.js +4 -1
  80. package/dist/components/select-menu.js.map +1 -1
  81. package/dist/components/shell.d.ts.map +1 -1
  82. package/dist/components/shell.js +8 -3
  83. package/dist/components/shell.js.map +1 -1
  84. package/dist/components/site.d.ts.map +1 -1
  85. package/dist/components/site.js +17 -13
  86. package/dist/components/site.js.map +1 -1
  87. package/dist/components/types.d.ts +102 -3
  88. package/dist/components/types.d.ts.map +1 -1
  89. package/dist/components/workspace.d.ts.map +1 -1
  90. package/dist/components/workspace.js +50 -34
  91. package/dist/components/workspace.js.map +1 -1
  92. package/dist/context.d.ts +39 -0
  93. package/dist/context.d.ts.map +1 -0
  94. package/dist/context.js +76 -0
  95. package/dist/context.js.map +1 -0
  96. package/dist/format.d.ts +33 -6
  97. package/dist/format.d.ts.map +1 -1
  98. package/dist/format.js +75 -10
  99. package/dist/format.js.map +1 -1
  100. package/dist/index.d.ts +3 -2
  101. package/dist/index.d.ts.map +1 -1
  102. package/dist/index.js +3 -2
  103. package/dist/index.js.map +1 -1
  104. package/dist/provider.d.ts +18 -11
  105. package/dist/provider.d.ts.map +1 -1
  106. package/dist/provider.js +11 -18
  107. package/dist/provider.js.map +1 -1
  108. package/dist/strings.d.ts +503 -0
  109. package/dist/strings.d.ts.map +1 -0
  110. package/dist/strings.js +537 -0
  111. package/dist/strings.js.map +1 -0
  112. package/package.json +1 -1
  113. package/src/components/admin.tsx +117 -93
  114. package/src/components/agents.tsx +55 -41
  115. package/src/components/app-chrome.tsx +6 -2
  116. package/src/components/approvals.tsx +26 -22
  117. package/src/components/building-blocks.tsx +6 -2
  118. package/src/components/charts.tsx +21 -11
  119. package/src/components/chat.tsx +45 -35
  120. package/src/components/commerce.tsx +61 -53
  121. package/src/components/data-display.tsx +38 -45
  122. package/src/components/data-table.tsx +20 -15
  123. package/src/components/developer.tsx +26 -15
  124. package/src/components/feedback.tsx +19 -7
  125. package/src/components/form.tsx +17 -9
  126. package/src/components/forms.tsx +131 -53
  127. package/src/components/foundation.tsx +23 -36
  128. package/src/components/inputs.tsx +4 -2
  129. package/src/components/mail.tsx +16 -11
  130. package/src/components/media.tsx +64 -21
  131. package/src/components/navigation.tsx +25 -13
  132. package/src/components/operations.tsx +40 -32
  133. package/src/components/previews.tsx +17 -15
  134. package/src/components/primitives.tsx +8 -5
  135. package/src/components/real-estate.tsx +55 -35
  136. package/src/components/rich-text-editor.tsx +20 -17
  137. package/src/components/select-menu.tsx +5 -2
  138. package/src/components/shell.tsx +8 -3
  139. package/src/components/site.tsx +18 -14
  140. package/src/components/types.ts +111 -3
  141. package/src/components/workspace.tsx +79 -60
  142. package/src/context.ts +112 -0
  143. package/src/format.ts +108 -15
  144. package/src/index.ts +43 -0
  145. package/src/provider.tsx +36 -40
  146. package/src/strings.ts +1500 -0
@@ -1,5 +1,7 @@
1
1
  "use client";
2
2
  import * as React from "react";
3
+ import { useStrings } from "../context.js";
4
+ import { SHELL_STRINGS } from "../strings.js";
3
5
  import { Icon } from "../Icon.js";
4
6
  import { cx, reduced } from "../cx.js";
5
7
  import { Avatar } from "./foundation.js";
@@ -16,8 +18,9 @@ import type {
16
18
  } from "./types.js";
17
19
 
18
20
  export function TopBar(p: TopBarProps) {
21
+ const t = useStrings(SHELL_STRINGS);
19
22
  return (
20
- <nav className="tf-topbar" aria-label="Main">
23
+ <nav className="tf-topbar" aria-label={t.mainNavigation}>
21
24
  {p.brand && (
22
25
  <span className="tf-brand">
23
26
  {p.brand}
@@ -88,8 +91,9 @@ function railBtn(it: RailItem, i: number) {
88
91
  }
89
92
 
90
93
  export function SideRail(p: SideRailProps) {
94
+ const t = useStrings(SHELL_STRINGS);
91
95
  return (
92
- <aside className="tf-rail" aria-label="Tools">
96
+ <aside className="tf-rail" aria-label={t.tools}>
93
97
  <div className="tf-rail-group">{(p.top || []).map(railBtn)}</div>
94
98
  <div className="tf-rail-group">{(p.bottom || []).map((it, i) => railBtn(it, i + 3))}</div>
95
99
  </aside>
@@ -97,12 +101,13 @@ export function SideRail(p: SideRailProps) {
97
101
  }
98
102
 
99
103
  export function Dock(p: DockProps) {
104
+ const t = useStrings(SHELL_STRINGS);
100
105
  return (
101
106
  <div
102
107
  className={cx("tf-dock", p.surface && "tf-" + p.surface, p.className)}
103
108
  style={p.style}
104
109
  role="toolbar"
105
- aria-label={p.label || "Quick actions"}
110
+ aria-label={p.label || t.quickActions}
106
111
  >
107
112
  {(p.items || []).map((it) => (
108
113
  <button
@@ -1,5 +1,7 @@
1
1
  "use client";
2
2
  import * as React from "react";
3
+ import { useStrings } from "../context.js";
4
+ import { SITE_STRINGS } from "../strings.js";
3
5
  import { useControlled } from "../hooks.js";
4
6
  import { cx } from "../cx.js";
5
7
  import { Icon } from "../Icon.js";
@@ -10,11 +12,12 @@ import type { AnnouncementBarProps, ChatLauncherProps, CookieConsentProps } from
10
12
 
11
13
  /* ── Site chrome: assistant launcher, cookie consent, announcement ── */
12
14
  export function ChatLauncher(p: ChatLauncherProps) {
15
+ const t = useStrings(SITE_STRINGS);
13
16
  const open = useControlled(p.open, false, p.onOpenChange);
14
17
  return (
15
18
  <div className={cx("tf-launch", open[0] && "open", p.inline && "inline")}>
16
19
  {open[0] && (
17
- <div className="tf-launch-panel" role="dialog" aria-label={p.title || "Assistant"}>
20
+ <div className="tf-launch-panel" role="dialog" aria-label={p.title || t.assistant}>
18
21
  <div className="tf-launch-head">
19
22
  <AgentMark tint={p.tint || "lilac"} size={32} />
20
23
  <div
@@ -23,14 +26,14 @@ export function ChatLauncher(p: ChatLauncherProps) {
23
26
  flex: 1,
24
27
  }}
25
28
  >
26
- <b>{p.title || "Assistant"}</b>
29
+ <b>{p.title || t.assistant}</b>
27
30
  {p.context && <small>{p.context}</small>}
28
31
  </div>
29
32
  {p.headerAction}
30
33
  <IconButton
31
34
  icon="x"
32
35
  size="sm"
33
- label="Close"
36
+ label={t.close}
34
37
  onClick={() => {
35
38
  open[1](false);
36
39
  }}
@@ -43,7 +46,7 @@ export function ChatLauncher(p: ChatLauncherProps) {
43
46
  <button
44
47
  type="button"
45
48
  className="tf-launch-btn"
46
- aria-label={open[0] ? "Close assistant" : p.title || "Open assistant"}
49
+ aria-label={open[0] ? t.closeAssistant : p.title || t.openAssistant}
47
50
  aria-expanded={open[0]}
48
51
  onClick={() => {
49
52
  open[1](!open[0]);
@@ -57,6 +60,7 @@ export function ChatLauncher(p: ChatLauncherProps) {
57
60
  }
58
61
 
59
62
  export function CookieConsent(p: CookieConsentProps) {
63
+ const t = useStrings(SITE_STRINGS);
60
64
  const more = React.useState(false),
61
65
  cats = React.useState(
62
66
  (p.categories || []).reduce<Record<string, boolean>>((a, c) => {
@@ -77,7 +81,7 @@ export function CookieConsent(p: CookieConsentProps) {
77
81
  <div
78
82
  className={cx("tf-cookie", p.inline && "inline")}
79
83
  role="dialog"
80
- aria-label={p.title || "Privacy settings"}
84
+ aria-label={p.title || t.privacySettings}
81
85
  >
82
86
  <div
83
87
  className="tf-row"
@@ -94,15 +98,14 @@ export function CookieConsent(p: CookieConsentProps) {
94
98
  gap: 4,
95
99
  }}
96
100
  >
97
- <b>{p.title || "Privacy settings"}</b>
101
+ <b>{p.title || t.privacySettings}</b>
98
102
  <p
99
103
  className="tf-card-desc"
100
104
  style={{
101
105
  margin: 0,
102
106
  }}
103
107
  >
104
- {p.text ||
105
- "We use cookies to run this site and, with your consent, to measure and improve it."}
108
+ {p.text || t.cookieText}
106
109
  {p.policy && <React.Fragment> {p.policy}</React.Fragment>}
107
110
  </p>
108
111
  </div>
@@ -121,7 +124,7 @@ export function CookieConsent(p: CookieConsentProps) {
121
124
  {c.text && <small>{c.text}</small>}
122
125
  </div>
123
126
  {c.required ? (
124
- <span className="tf-card-desc">{"Always on"}</span>
127
+ <span className="tf-card-desc">{t.alwaysOn}</span>
125
128
  ) : (
126
129
  <Switch
127
130
  checked={!!cats[0][c.id]}
@@ -144,7 +147,7 @@ export function CookieConsent(p: CookieConsentProps) {
144
147
  done(undefined);
145
148
  }}
146
149
  >
147
- {"Save choice"}
150
+ {t.saveChoice}
148
151
  </Button>
149
152
  ) : (
150
153
  <Button
@@ -153,7 +156,7 @@ export function CookieConsent(p: CookieConsentProps) {
153
156
  more[1](true);
154
157
  }}
155
158
  >
156
- {"Settings"}
159
+ {t.settings}
157
160
  </Button>
158
161
  )}
159
162
  <Button
@@ -162,14 +165,14 @@ export function CookieConsent(p: CookieConsentProps) {
162
165
  done(false);
163
166
  }}
164
167
  >
165
- {"Only necessary"}
168
+ {t.onlyNecessary}
166
169
  </Button>
167
170
  <Button
168
171
  onClick={() => {
169
172
  done(true);
170
173
  }}
171
174
  >
172
- {"Accept all"}
175
+ {t.acceptAll}
173
176
  </Button>
174
177
  </div>
175
178
  </div>
@@ -177,6 +180,7 @@ export function CookieConsent(p: CookieConsentProps) {
177
180
  }
178
181
 
179
182
  export function AnnouncementBar(p: AnnouncementBarProps) {
183
+ const t = useStrings(SITE_STRINGS);
180
184
  const shut = React.useState(false);
181
185
  if (shut[0]) return null;
182
186
  return (
@@ -188,7 +192,7 @@ export function AnnouncementBar(p: AnnouncementBarProps) {
188
192
  <button
189
193
  type="button"
190
194
  className="tf-announce-x"
191
- aria-label="Dismiss"
195
+ aria-label={t.dismiss}
192
196
  onClick={() => {
193
197
  shut[1](true);
194
198
  p.onDismiss && p.onDismiss();
@@ -21,23 +21,51 @@ export interface IconProps extends BaseProps {
21
21
  label?: string;
22
22
  className?: string;
23
23
  }
24
- export interface ButtonProps extends BaseProps {
24
+ /**
25
+ * Native attributes `Button` and `IconButton` pass to their `<button>` (or, with `asChild`, to the
26
+ * child). Every other attribute of `<button>` (`data-*`, events such as `onKeyDown`, `ref` in
27
+ * React 19) is passed on as well; these are the ones worth knowing.
28
+ */
29
+ export interface NativeButtonProps {
30
+ id?: string;
31
+ /** Form field name and value, sent with the form when this button submits it. */
32
+ name?: string;
33
+ value?: string;
34
+ /** The id of the form this button belongs to, when it sits outside it. */
35
+ form?: string;
36
+ title?: string;
37
+ tabIndex?: number;
38
+ autoFocus?: boolean;
39
+ "aria-label"?: string;
40
+ "aria-labelledby"?: string;
41
+ "aria-describedby"?: string;
42
+ /** For disclosure and menu triggers: whether what the button controls is open. */
43
+ "aria-expanded"?: boolean | "true" | "false";
44
+ "aria-controls"?: string;
45
+ "aria-haspopup"?: boolean | "true" | "false" | "menu" | "listbox" | "tree" | "grid" | "dialog";
46
+ /** For toggle buttons. */
47
+ "aria-pressed"?: boolean | "true" | "false" | "mixed";
48
+ "aria-current"?: boolean | "true" | "false" | "page" | "step" | "location" | "date" | "time";
49
+ }
50
+ export interface ButtonProps extends BaseProps, NativeButtonProps {
25
51
  variant?: "primary" | "secondary" | "soft" | "ghost" | "danger" | "danger-solid";
26
52
  size?: "md" | "sm";
27
53
  icon?: IconName;
28
54
  iconRight?: IconName;
29
55
  disabled?: boolean;
30
- type?: "button" | "submit";
56
+ type?: "button" | "submit" | "reset";
31
57
  onClick?: (e: MouseEvent<HTMLButtonElement>) => void;
32
58
  children?: ReactNode;
33
59
  /** Render the single child element (a link, a router Link) with the button's look instead of a <button>. */
34
60
  asChild?: boolean;
35
61
  }
36
- export interface IconButtonProps extends BaseProps {
62
+ export interface IconButtonProps extends BaseProps, NativeButtonProps {
37
63
  icon: IconName;
64
+ /** Accessible name and tooltip (`aria-label` and `title`); `aria-label` or `title` override them. */
38
65
  label: string;
39
66
  variant?: "soft" | "solid" | "outline" | "ghost";
40
67
  size?: "sm" | "md" | "lg";
68
+ type?: "button" | "submit" | "reset";
41
69
  onClick?: (e: MouseEvent<HTMLButtonElement>) => void;
42
70
  disabled?: boolean;
43
71
  /** Render the single child element (a link) with the button's look; the icon is placed inside it. */
@@ -107,6 +135,8 @@ export interface TextareaProps extends FieldProps, BaseProps {
107
135
  }
108
136
  export interface SearchFieldProps extends BaseProps {
109
137
  placeholder?: string;
138
+ /** Accessible name (default: the placeholder, or "Search"). */
139
+ label?: string;
110
140
  shortcut?: string;
111
141
  value?: string;
112
142
  onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
@@ -298,8 +328,17 @@ export interface BreadcrumbProps extends BaseProps {
298
328
  items: string[];
299
329
  }
300
330
  export interface PaginationProps extends BaseProps {
331
+ /** Number of pages. */
301
332
  total: number;
333
+ /**
334
+ * The current page (1-based). Controlled together with `onChange`; without `onChange` it is
335
+ * only the start page, as in earlier versions (prefer `defaultPage` for that).
336
+ */
302
337
  page?: number;
338
+ /** Start page when uncontrolled (default 1). */
339
+ defaultPage?: number;
340
+ /** A page was picked (previous, next or a number); receives the new 1-based page. */
341
+ onChange?: (page: number) => void;
303
342
  }
304
343
  export interface AppShellProps extends BaseProps {
305
344
  active?: string;
@@ -607,6 +646,7 @@ export interface FormFieldProps extends BaseProps {
607
646
  children?: ReactNode;
608
647
  }
609
648
  export interface TextFieldProps extends Omit<FormFieldProps, "children"> {
649
+ /** Input type (`"text"` by default): `"email"`, `"number"`, `"tel"`, `"url"`, `"password"` … */
610
650
  type?: string;
611
651
  icon?: IconName;
612
652
  suffix?: ReactNode;
@@ -614,7 +654,23 @@ export interface TextFieldProps extends Omit<FormFieldProps, "children"> {
614
654
  defaultValue?: string;
615
655
  placeholder?: string;
616
656
  disabled?: boolean;
657
+ readOnly?: boolean;
617
658
  autoComplete?: string;
659
+ autoFocus?: boolean;
660
+ /** Smallest value for `type="number"`, `"date"` and the like (native `min`). */
661
+ min?: number | string;
662
+ /** Largest value (native `max`). */
663
+ max?: number | string;
664
+ /** Step between valid values (native `step`), e.g. `1` for whole numbers or `"any"`. */
665
+ step?: number | string;
666
+ /** Fewest characters (native `minlength`). */
667
+ minLength?: number;
668
+ /** Most characters (native `maxlength`). */
669
+ maxLength?: number;
670
+ /** Pattern the value must match (native `pattern`). */
671
+ pattern?: string;
672
+ /** Virtual keyboard on touch devices (native `inputmode`), e.g. `"numeric"` or `"decimal"`. */
673
+ inputMode?: "none" | "text" | "tel" | "url" | "email" | "numeric" | "decimal" | "search";
618
674
  onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
619
675
  onBlur?: (e: ChangeEvent<HTMLInputElement>) => void;
620
676
  }
@@ -720,13 +776,34 @@ export interface UploadFile {
720
776
  id: string;
721
777
  name: string;
722
778
  size: number;
779
+ /** Upload progress 0–100: a bar while below 100, "uploaded" at 100. */
723
780
  progress: number;
781
+ /** The picked or dropped file (set by FileDrop for files it adds). */
782
+ file?: File;
724
783
  }
725
784
  export interface FileDropProps extends BaseProps {
785
+ /** The listed files (controlled); set `progress` per file to show real upload progress. */
726
786
  files?: UploadFile[];
787
+ /** The list changed: files added (with their `file`) or removed. */
727
788
  onChange?: (f: UploadFile[]) => void;
789
+ /**
790
+ * The person picked or dropped files: the real `File` objects, after `accept` and `multiple`.
791
+ * Upload them yourself. To show progress, control `files` and set each `progress`; an
792
+ * uncontrolled list shows them with their size only.
793
+ */
794
+ onFiles?: (files: File[]) => void;
795
+ /** Dropped files that do not match `accept` (show an inline Alert). */
796
+ onReject?: (files: File[]) => void;
797
+ /** A listed file was removed or its upload cancelled. */
798
+ onRemove?: (f: UploadFile) => void;
799
+ /**
800
+ * Animate made-up progress for added files, as a demo of the look. Default: on without
801
+ * `onFiles` (as before), off with it.
802
+ */
803
+ simulateProgress?: boolean;
728
804
  title?: string;
729
805
  hint?: string;
806
+ /** Accepted types, as for `<input type="file">` ("image/*,.pdf"); also checked on drop. */
730
807
  accept?: string;
731
808
  multiple?: boolean;
732
809
  }
@@ -1114,6 +1191,8 @@ export interface PlanCardProps extends BaseProps {
1114
1191
  flag?: string;
1115
1192
  current?: boolean;
1116
1193
  cta?: string;
1194
+ /** Disable the button, e.g. while a checkout starts or when the plan cannot be picked. */
1195
+ disabled?: boolean;
1117
1196
  onPick?: () => void;
1118
1197
  }
1119
1198
 
@@ -2108,6 +2187,17 @@ export interface ImageVariantsProps extends BaseProps {
2108
2187
  tint?: Tint;
2109
2188
  actions?: ReactNode;
2110
2189
  }
2190
+ /** `referrerPolicy` values of `<img>`. */
2191
+ export type ImageReferrerPolicy =
2192
+ | ""
2193
+ | "no-referrer"
2194
+ | "no-referrer-when-downgrade"
2195
+ | "origin"
2196
+ | "origin-when-cross-origin"
2197
+ | "same-origin"
2198
+ | "strict-origin"
2199
+ | "strict-origin-when-cross-origin"
2200
+ | "unsafe-url";
2111
2201
  export interface GalleryItem {
2112
2202
  src?: string;
2113
2203
  alt?: string;
@@ -2117,6 +2207,13 @@ export interface GalleryItem {
2117
2207
  }
2118
2208
  export interface GalleryProps extends BaseProps {
2119
2209
  items: GalleryItem[];
2210
+ /**
2211
+ * Loading of the main image: `"lazy"` (default) waits until the gallery is near the viewport;
2212
+ * use `"eager"` for a gallery at the top of the page. Thumbnails always load lazily.
2213
+ */
2214
+ loading?: "lazy" | "eager";
2215
+ /** `referrerPolicy` of every image, e.g. `"no-referrer"` for photos from other hosts. */
2216
+ referrerPolicy?: ImageReferrerPolicy;
2120
2217
  start?: number;
2121
2218
  ratio?: string;
2122
2219
  thumbs?: boolean;
@@ -2136,6 +2233,17 @@ export interface BeforeAfterProps extends BaseProps {
2136
2233
  ratio?: string;
2137
2234
  beforeLabel?: string;
2138
2235
  afterLabel?: string;
2236
+ /** Accessible name of the slider (default "Compare before and after"). */
2237
+ label?: string;
2238
+ /**
2239
+ * What screen readers hear for a position (0–100, the share of "before"). Default:
2240
+ * "Before 40%, After 60%", with your `beforeLabel`/`afterLabel`.
2241
+ */
2242
+ valueText?: (percent: number) => string;
2243
+ /** Loading of both images (default `"lazy"`). */
2244
+ loading?: "lazy" | "eager";
2245
+ /** `referrerPolicy` of both images. */
2246
+ referrerPolicy?: ImageReferrerPolicy;
2139
2247
  }
2140
2248
 
2141
2249
  /* ── Kit 5: real estate ── */