@vamos-ui/react 0.3.0 → 0.4.1

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 (274) hide show
  1. package/README.md +4 -0
  2. package/dist/blocks/block-heading.js +1 -1
  3. package/dist/blocks/block-image.js +1 -1
  4. package/dist/blocks/block-link.js +2 -2
  5. package/dist/blocks/index.d.ts +5 -5
  6. package/dist/blocks/index.js +5 -5
  7. package/dist/blocks/labels.d.ts +8 -0
  8. package/dist/blocks/labels.js +60 -0
  9. package/dist/blocks/section-header.js +1 -1
  10. package/dist/blocks/section.js +2 -2
  11. package/dist/blocks/site/_kit-1.js +1 -1
  12. package/dist/blocks/site/announcement-bar.js +1 -1
  13. package/dist/blocks/site/article-layout.d.ts +1 -0
  14. package/dist/blocks/site/article-layout.js +2 -1
  15. package/dist/blocks/site/blog-list.d.ts +1 -0
  16. package/dist/blocks/site/blog-list.js +3 -2
  17. package/dist/blocks/site/contact-dock.js +3 -1
  18. package/dist/blocks/site/contact-form.js +1 -1
  19. package/dist/blocks/site/cta.d.ts +2 -2
  20. package/dist/blocks/site/cta.js +6 -4
  21. package/dist/blocks/site/feature-grid.d.ts +1 -0
  22. package/dist/blocks/site/feature-grid.js +5 -4
  23. package/dist/blocks/site/feature-tabs.js +1 -1
  24. package/dist/blocks/site/footer.d.ts +11 -2
  25. package/dist/blocks/site/footer.js +36 -11
  26. package/dist/blocks/site/gallery-section.d.ts +6 -1
  27. package/dist/blocks/site/gallery-section.js +5 -4
  28. package/dist/blocks/site/hero.d.ts +3 -2
  29. package/dist/blocks/site/hero.js +7 -5
  30. package/dist/blocks/site/logo-strip.d.ts +1 -0
  31. package/dist/blocks/site/logo-strip.js +1 -1
  32. package/dist/blocks/site/map-hours.d.ts +2 -2
  33. package/dist/blocks/site/map-hours.js +4 -2
  34. package/dist/blocks/site/media-text.d.ts +4 -1
  35. package/dist/blocks/site/media-text.js +4 -3
  36. package/dist/blocks/site/menu-list.d.ts +7 -3
  37. package/dist/blocks/site/menu-list.js +34 -7
  38. package/dist/blocks/site/navbar.d.ts +1 -0
  39. package/dist/blocks/site/navbar.js +6 -5
  40. package/dist/blocks/site/not-found.js +2 -1
  41. package/dist/blocks/site/page-intro.d.ts +1 -0
  42. package/dist/blocks/site/page-intro.js +2 -1
  43. package/dist/blocks/site/process.d.ts +1 -0
  44. package/dist/blocks/site/process.js +2 -1
  45. package/dist/blocks/site/registry-1.d.ts +1 -1
  46. package/dist/blocks/site/registry-2.d.ts +5 -0
  47. package/dist/blocks/site/registry-2.js +5 -3
  48. package/dist/blocks/site/rich-text-section.js +2 -1
  49. package/dist/blocks/site/shared/heading-lines.d.ts +9 -0
  50. package/dist/blocks/site/shared/heading-lines.js +32 -0
  51. package/dist/blocks/site/shared/image-sizes.d.ts +25 -0
  52. package/dist/blocks/site/shared/image-sizes.js +37 -0
  53. package/dist/blocks/site/shared/island-keys.d.ts +1 -1
  54. package/dist/blocks/site/shared/island-keys.js +1 -1
  55. package/dist/blocks/site/shared/labels-2.d.ts +17 -1
  56. package/dist/blocks/site/shared/labels-2.js +832 -6
  57. package/dist/blocks/site/shared/open-now.d.ts +1 -1
  58. package/dist/blocks/site/shared/open-now.js +1 -1
  59. package/dist/blocks/site/shared/opening-hours.d.ts +18 -2
  60. package/dist/blocks/site/shared/opening-hours.js +36 -7
  61. package/dist/blocks/site/shared/tap.d.ts +9 -0
  62. package/dist/blocks/site/shared/tap.js +16 -0
  63. package/dist/blocks/site/site-shell.js +3 -3
  64. package/dist/blocks/site/team.d.ts +1 -1
  65. package/dist/blocks/site/team.js +4 -3
  66. package/dist/blocks/site/testimonials.d.ts +2 -2
  67. package/dist/blocks/site/testimonials.js +3 -3
  68. package/dist/business/approval-flow.js +2 -2
  69. package/dist/business/import-wizard.js +1 -1
  70. package/dist/business/line-items.js +1 -1
  71. package/dist/business/multi-step-form.js +2 -2
  72. package/dist/business/permission-matrix.js +1 -1
  73. package/dist/business/setup-checklist.js +2 -2
  74. package/dist/business/signer-status.js +1 -1
  75. package/dist/charts/bar-chart.js +1 -1
  76. package/dist/charts/bar-list.js +1 -1
  77. package/dist/charts/chart-shell.d.ts +9 -2
  78. package/dist/charts/chart-shell.js +11 -5
  79. package/dist/charts/chart.js +1 -1
  80. package/dist/charts/combo-chart.js +5 -7
  81. package/dist/charts/donut-chart.js +1 -1
  82. package/dist/charts/funnel.js +1 -1
  83. package/dist/charts/gauge.js +2 -2
  84. package/dist/charts/utils.d.ts +10 -0
  85. package/dist/charts/utils.js +46 -0
  86. package/dist/components/accordion.d.ts +1 -1
  87. package/dist/components/accordion.js +8 -8
  88. package/dist/components/activity-timeline.js +11 -11
  89. package/dist/components/address-field.js +3 -3
  90. package/dist/components/alert-dialog.d.ts +1 -1
  91. package/dist/components/alert-dialog.js +8 -8
  92. package/dist/components/alert.js +2 -2
  93. package/dist/components/app-shell.js +3 -3
  94. package/dist/components/aspect-ratio.d.ts +26 -0
  95. package/dist/components/aspect-ratio.js +42 -0
  96. package/dist/components/attachment-list.js +2 -2
  97. package/dist/components/audit-log.js +1 -1
  98. package/dist/components/avatar.d.ts +1 -1
  99. package/dist/components/avatar.js +8 -8
  100. package/dist/components/backup-codes.js +1 -1
  101. package/dist/components/badge.js +3 -3
  102. package/dist/components/breadcrumb.js +10 -9
  103. package/dist/components/button-group.js +4 -4
  104. package/dist/components/button.js +4 -4
  105. package/dist/components/calendar.js +5 -5
  106. package/dist/components/card.js +8 -8
  107. package/dist/components/carousel.d.ts +12 -3
  108. package/dist/components/carousel.js +17 -14
  109. package/dist/components/checkbox.d.ts +1 -1
  110. package/dist/components/checkbox.js +6 -6
  111. package/dist/components/collapsible.d.ts +36 -0
  112. package/dist/components/collapsible.js +37 -0
  113. package/dist/components/color-picker.js +3 -3
  114. package/dist/components/combobox.js +1 -1
  115. package/dist/components/command.js +9 -9
  116. package/dist/components/comment-thread.js +3 -3
  117. package/dist/components/context-menu.d.ts +1 -1
  118. package/dist/components/context-menu.js +9 -9
  119. package/dist/components/currency-input.js +1 -1
  120. package/dist/components/date-picker.js +2 -2
  121. package/dist/components/date-range-picker.js +1 -1
  122. package/dist/components/description-list.js +2 -2
  123. package/dist/components/dialog.d.ts +1 -1
  124. package/dist/components/dialog.js +9 -9
  125. package/dist/components/dropdown-menu.d.ts +1 -1
  126. package/dist/components/dropdown-menu.js +9 -9
  127. package/dist/components/editor-layout.js +9 -9
  128. package/dist/components/empty-state.js +2 -2
  129. package/dist/components/entity-card.js +1 -1
  130. package/dist/components/file-upload.js +5 -5
  131. package/dist/components/formatted-input.js +3 -3
  132. package/dist/components/hierarchy-chart.js +1 -1
  133. package/dist/components/hover-card.d.ts +1 -1
  134. package/dist/components/hover-card.js +3 -3
  135. package/dist/components/iban-input.js +1 -1
  136. package/dist/components/id-input.js +3 -3
  137. package/dist/components/image.d.ts +18 -2
  138. package/dist/components/image.js +16 -9
  139. package/dist/components/input-otp.js +6 -6
  140. package/dist/components/input.d.ts +1 -1
  141. package/dist/components/input.js +6 -6
  142. package/dist/components/item.js +4 -4
  143. package/dist/components/kbd.js +3 -3
  144. package/dist/components/list-layout.js +9 -9
  145. package/dist/components/menubar.d.ts +96 -0
  146. package/dist/components/menubar.js +123 -0
  147. package/dist/components/native-select.js +1 -1
  148. package/dist/components/navigation-menu.d.ts +1 -1
  149. package/dist/components/navigation-menu.js +12 -11
  150. package/dist/components/notification-center.js +4 -4
  151. package/dist/components/page-header.js +3 -3
  152. package/dist/components/pagination.js +9 -9
  153. package/dist/components/phone-input.js +1 -1
  154. package/dist/components/pin-map.js +1 -1
  155. package/dist/components/placeholder-art.d.ts +51 -0
  156. package/dist/components/placeholder-art.js +82 -0
  157. package/dist/components/popover.d.ts +1 -1
  158. package/dist/components/popover.js +7 -7
  159. package/dist/components/progress.js +3 -3
  160. package/dist/components/qr-code.js +1 -1
  161. package/dist/components/radio-group.d.ts +1 -1
  162. package/dist/components/radio-group.js +4 -4
  163. package/dist/components/record-detail-layout.js +10 -10
  164. package/dist/components/record-picker.js +2 -2
  165. package/dist/components/resizable.js +2 -2
  166. package/dist/components/scroll-area.d.ts +1 -1
  167. package/dist/components/scroll-area.js +4 -4
  168. package/dist/components/select.d.ts +1 -1
  169. package/dist/components/select.js +10 -10
  170. package/dist/components/separator.d.ts +1 -1
  171. package/dist/components/separator.js +3 -3
  172. package/dist/components/settings-layout.js +6 -6
  173. package/dist/components/sheet.js +3 -3
  174. package/dist/components/sidebar.js +12 -11
  175. package/dist/components/signature-pad.js +1 -1
  176. package/dist/components/skeleton.js +5 -5
  177. package/dist/components/sla-timer.js +2 -2
  178. package/dist/components/slider.d.ts +1 -1
  179. package/dist/components/slider.js +2 -2
  180. package/dist/components/slug-input.js +1 -1
  181. package/dist/components/sparkline.js +1 -1
  182. package/dist/components/spinner.js +2 -2
  183. package/dist/components/stat.js +5 -5
  184. package/dist/components/status-picker.js +2 -2
  185. package/dist/components/stepper.js +1 -1
  186. package/dist/components/switch.d.ts +1 -1
  187. package/dist/components/switch.js +3 -3
  188. package/dist/components/table.js +10 -10
  189. package/dist/components/tabs.d.ts +1 -1
  190. package/dist/components/tabs.js +11 -11
  191. package/dist/components/tag-input.js +1 -1
  192. package/dist/components/task-list.js +1 -1
  193. package/dist/components/time-picker.js +3 -3
  194. package/dist/components/toggle.d.ts +2 -1
  195. package/dist/components/toggle.js +7 -6
  196. package/dist/components/tooltip.d.ts +1 -1
  197. package/dist/components/tooltip.js +5 -4
  198. package/dist/components/top-bar.js +4 -4
  199. package/dist/components/tour.js +1 -1
  200. package/dist/components/tree-select.js +2 -2
  201. package/dist/components/tree-view.js +3 -3
  202. package/dist/components/typography.js +11 -11
  203. package/dist/components/user-picker.js +2 -2
  204. package/dist/components/version-history.js +3 -3
  205. package/dist/data-table/data-table.js +1 -1
  206. package/dist/data-table/filter-bar.js +2 -2
  207. package/dist/data-table/index.d.ts +15 -8
  208. package/dist/data-table/index.js +9 -8
  209. package/dist/data-table/saved-views.js +1 -1
  210. package/dist/editor/block-editor.js +1 -1
  211. package/dist/editor/context.js +1 -1
  212. package/dist/editor/menus.js +1 -1
  213. package/dist/fonts/font-picker.js +3 -3
  214. package/dist/fonts/pairing-picker.js +1 -1
  215. package/dist/fonts/provider.js +1 -1
  216. package/dist/index.d.ts +188 -90
  217. package/dist/index.js +94 -90
  218. package/dist/lib/data-islands.js +1 -1
  219. package/dist/lib/field-context.js +1 -1
  220. package/dist/lib/floating-arrow.js +1 -1
  221. package/dist/lib/islands.js +1 -1
  222. package/dist/lib/layer.js +3 -3
  223. package/dist/lib/locale.js +2 -2
  224. package/dist/lib/menu.js +2 -2
  225. package/dist/lib/provider.js +4 -4
  226. package/dist/lib/theme-scope.js +4 -3
  227. package/dist/lib/value-format.js +1 -1
  228. package/dist/lib/variants.js +2 -2
  229. package/dist/locales/ar.d.ts +2087 -0
  230. package/dist/locales/ar.js +2088 -0
  231. package/dist/locales/de.d.ts +2087 -0
  232. package/dist/locales/de.js +2088 -0
  233. package/dist/locales/en.d.ts +1 -0
  234. package/dist/locales/en.js +1 -0
  235. package/dist/locales/es.d.ts +2087 -0
  236. package/dist/locales/es.js +2087 -0
  237. package/dist/locales/fr.d.ts +2087 -0
  238. package/dist/locales/fr.js +2088 -0
  239. package/dist/locales/tr.d.ts +1 -0
  240. package/dist/locales/tr.js +1 -0
  241. package/dist/media/focal-point.js +1 -1
  242. package/dist/media/gallery.js +1 -1
  243. package/dist/media/image-cropper.js +1 -1
  244. package/dist/media/image-field.js +2 -2
  245. package/dist/media/lightbox.js +4 -3
  246. package/dist/media/link-preview.js +3 -3
  247. package/dist/media/media-library.js +4 -4
  248. package/dist/media/media-picker.js +1 -1
  249. package/dist/media/media-provider.js +1 -1
  250. package/dist/media/video-player.js +4 -4
  251. package/dist/motion/count-up.js +1 -1
  252. package/dist/motion/motion-scope.js +2 -2
  253. package/dist/motion/page-transition.js +1 -1
  254. package/dist/motion/parallax.js +2 -2
  255. package/dist/motion/pointer.js +3 -3
  256. package/dist/motion/reveal.js +3 -3
  257. package/dist/motion/skeleton-swap.js +1 -1
  258. package/dist/motion/text-reveal.d.ts +3 -1
  259. package/dist/motion/text-reveal.js +6 -4
  260. package/dist/motion/ticker.js +1 -1
  261. package/dist/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  262. package/dist/render/block-renderer.js +1 -1
  263. package/dist/scheduler/gantt.js +2 -2
  264. package/dist/scheduler/resource-calendar.js +2 -2
  265. package/dist/scheduler/scheduler.js +3 -3
  266. package/dist/scheduler/time-tracker.js +4 -4
  267. package/dist/sortable/kanban.js +2 -2
  268. package/dist/sortable/sortable-list.js +2 -2
  269. package/dist/sortable/sortable.js +4 -4
  270. package/dist/styles/blocks.css +18 -9
  271. package/dist/styles/editors.css +2 -1
  272. package/dist/styles/media.css +31 -5
  273. package/dist/styles.css +39 -9
  274. package/package.json +1 -1
@@ -15,7 +15,7 @@ export interface OpenNowProps {
15
15
  className?: string;
16
16
  }
17
17
  /**
18
- * "Open now · closes at 22:00" — computed in the business's time zone on the client, refreshed
18
+ * "Open · until 10 PM" / "Closed · opens tomorrow at 12 PM" — computed in the business's time zone on the client, refreshed
19
19
  * every minute. Renders nothing on the server and without JS: a cached page never shows a stale
20
20
  * status. ~1 KB.
21
21
  */
@@ -4,7 +4,7 @@ import * as React from "react";
4
4
  import { cn2 as cn } from "./kit-2.js";
5
5
  import { describeStatus, hoursStatus } from "./opening-hours.js";
6
6
  /**
7
- * "Open now · closes at 22:00" — computed in the business's time zone on the client, refreshed
7
+ * "Open · until 10 PM" / "Closed · opens tomorrow at 12 PM" — computed in the business's time zone on the client, refreshed
8
8
  * every minute. Renders nothing on the server and without JS: a cached page never shows a stale
9
9
  * status. ~1 KB.
10
10
  */
@@ -110,8 +110,24 @@ export declare function summarizeHours(hours: OpeningHours, locale?: string): {
110
110
  }[];
111
111
  /** schema.org `OpeningHoursSpecification[]` for JSON-LD (weekly + special days). */
112
112
  export declare function openingHoursJsonLd(hours: OpeningHours): Record<string, unknown>[];
113
- /** The status sentence: "Open now · closes at 22:00", "Closed · opens Thu at 12:00". */
114
- export declare function describeStatus(s: OpenStatus, labels: Record<"openNow" | "closesAt" | "closingSoon" | "closed" | "closedToday" | "opensAt" | "opensTodayAt" | "open24h", string>, locale?: string): {
113
+ /** Label keys `describeStatus` reads. */
114
+ export type StatusLabelKey = "openNow" | "openUntil" | "closingSoon" | "closingSoonUntil" | "openAllDay" | "closed" | "closedToday" | "opensAt" | "opensTodayAt" | "opensTomorrowAt";
115
+ /**
116
+ * Variables for a time in a status template: `{time}` ("01:00", "1 AM"), plus `{timeTo}` /
117
+ * `{timeAt}` — the time with the Turkish dative / locative suffix ("01:00’e", "12:00’de") so the
118
+ * TR strings read naturally; other locales get the plain time.
119
+ */
120
+ export declare function timeVars(hhmm: string, locale?: string): {
121
+ time: string;
122
+ timeTo: string;
123
+ timeAt: string;
124
+ };
125
+ /**
126
+ * The status as `{ head, tail }`, each said once: "Open · until 1 AM", "Closing soon · open until
127
+ * 1 AM", "Open · 24 hours", "Closed · opens tomorrow at 12 PM", "Closed today · Staff day · opens
128
+ * Thu at 12 PM". TR: "Açık · 01:00’e kadar", "Kapalı · yarın 12:00’de açılıyor".
129
+ */
130
+ export declare function describeStatus(s: OpenStatus, labels: Record<StatusLabelKey, string>, locale?: string): {
115
131
  head: string;
116
132
  tail?: string;
117
133
  };
@@ -227,19 +227,48 @@ export function openingHoursJsonLd(hours) {
227
227
  }
228
228
  return out;
229
229
  }
230
- /** The status sentence: "Open now · closes at 22:00", "Closed · opens Thu at 12:00". */
230
+ // Turkish case suffixes on a clock time follow the last spoken word: "01:00" is read "bir" →
231
+ // "01:00’e" (dative) / "01:00’de" (locative); "22:30" ends in "otuz" → "22:30’a" / "22:30’da".
232
+ const TR_UNITS_DAT = ["", "e", "ye", "e", "e", "e", "ya", "ye", "e", "a"];
233
+ const TR_UNITS_LOC = ["", "de", "de", "te", "te", "te", "da", "de", "de", "da"];
234
+ const TR_TENS_DAT = ["a", "a", "ye", "a", "a", "ye"]; // sıfır, on, yirmi, otuz, kırk, elli
235
+ const TR_TENS_LOC = ["da", "da", "de", "da", "ta", "de"];
236
+ function trSuffix(hhmm, kind) {
237
+ const [h = 0, m = 0] = hhmm.split(":").map(Number);
238
+ const n = m === 0 ? h % 24 : m; // the last word read aloud
239
+ const unit = n % 10;
240
+ if (unit)
241
+ return (kind === "dat" ? TR_UNITS_DAT : TR_UNITS_LOC)[unit];
242
+ return (kind === "dat" ? TR_TENS_DAT : TR_TENS_LOC)[Math.floor(n / 10)];
243
+ }
244
+ /**
245
+ * Variables for a time in a status template: `{time}` ("01:00", "1 AM"), plus `{timeTo}` /
246
+ * `{timeAt}` — the time with the Turkish dative / locative suffix ("01:00’e", "12:00’de") so the
247
+ * TR strings read naturally; other locales get the plain time.
248
+ */
249
+ export function timeVars(hhmm, locale = "en-US") {
250
+ const time = formatTime(hhmm, locale);
251
+ if (!/^tr\b/i.test(locale))
252
+ return { time, timeTo: time, timeAt: time };
253
+ return { time, timeTo: `${time}’${trSuffix(hhmm, "dat")}`, timeAt: `${time}’${trSuffix(hhmm, "loc")}` };
254
+ }
255
+ /**
256
+ * The status as `{ head, tail }`, each said once: "Open · until 1 AM", "Closing soon · open until
257
+ * 1 AM", "Open · 24 hours", "Closed · opens tomorrow at 12 PM", "Closed today · Staff day · opens
258
+ * Thu at 12 PM". TR: "Açık · 01:00’e kadar", "Kapalı · yarın 12:00’de açılıyor".
259
+ */
231
260
  export function describeStatus(s, labels, locale = "en-US") {
232
261
  const f = (tpl, vars) => formatMessage(tpl, vars, locale);
233
262
  if (s.state !== "closed") {
234
263
  if (s.allDay)
235
- return { head: f(labels.openNow), tail: f(labels.open24h) };
236
- const tail = f(labels.closesAt, { time: formatTime(s.closesAt, locale) });
237
- return { head: f(s.state === "closing-soon" ? labels.closingSoon : labels.openNow), tail };
264
+ return { head: f(labels.openNow), tail: f(labels.openAllDay) };
265
+ const vars = timeVars(s.closesAt, locale);
266
+ return s.state === "closing-soon" ? { head: f(labels.closingSoon), tail: f(labels.closingSoonUntil, vars) } : { head: f(labels.openNow), tail: f(labels.openUntil, vars) };
238
267
  }
239
268
  const head = s.special?.closed ? (s.special.note ? `${f(labels.closedToday)} · ${s.special.note}` : f(labels.closedToday)) : f(labels.closed);
240
269
  if (!s.opensAt)
241
270
  return { head };
242
- const time = formatTime(s.opensAt.time, locale);
243
- const tail = s.opensAt.dayOffset === 0 ? f(labels.opensTodayAt, { time }) : f(labels.opensAt, { day: weekdayName(s.opensAt.weekday, locale, "short"), time });
244
- return { head, tail };
271
+ const vars = { ...timeVars(s.opensAt.time, locale), day: weekdayName(s.opensAt.weekday, locale, "short") };
272
+ const tpl = s.opensAt.dayOffset === 0 ? labels.opensTodayAt : s.opensAt.dayOffset === 1 ? labels.opensTomorrowAt : labels.opensAt;
273
+ return { head, tail: f(tpl, vars) };
245
274
  }
@@ -0,0 +1,9 @@
1
+ /** ≥ 24×24 CSS px everywhere (WCAG 2.5.8), ≥ 44px tall on touch. For text links in lists. */
2
+ export declare const TAP = "inline-flex min-h-6 items-center pointer-coarse:min-h-11";
3
+ /** A square icon control: ≥ 24px everywhere, 44×44 on touch. Combine with the control's own size. */
4
+ export declare const TAP_ICON = "min-h-6 min-w-6 pointer-coarse:min-h-11 pointer-coarse:min-w-11";
5
+ /**
6
+ * WCAG 2.5.3 Label in Name: an `aria-label` must contain the visible label. Returns `name` when
7
+ * it already does (case-insensitive), else `"<visible>, <name>"`.
8
+ */
9
+ export declare function nameWithLabel(visible: string | undefined, name: string): string;
@@ -0,0 +1,16 @@
1
+ // Tap-target sizing for site blocks (WCAG 2.5.8 + touch comfort). Padding/min-size only — the
2
+ // visual stays the same on a mouse; on touch (`pointer: coarse`) primary controls grow to 44px.
3
+ /** ≥ 24×24 CSS px everywhere (WCAG 2.5.8), ≥ 44px tall on touch. For text links in lists. */
4
+ export const TAP = "inline-flex min-h-6 items-center pointer-coarse:min-h-11";
5
+ /** A square icon control: ≥ 24px everywhere, 44×44 on touch. Combine with the control's own size. */
6
+ export const TAP_ICON = "min-h-6 min-w-6 pointer-coarse:min-h-11 pointer-coarse:min-w-11";
7
+ /**
8
+ * WCAG 2.5.3 Label in Name: an `aria-label` must contain the visible label. Returns `name` when
9
+ * it already does (case-insensitive), else `"<visible>, <name>"`.
10
+ */
11
+ export function nameWithLabel(visible, name) {
12
+ const v = visible?.trim();
13
+ if (!v)
14
+ return name;
15
+ return name.toLocaleLowerCase().includes(v.toLocaleLowerCase()) ? name : `${v}, ${name}`;
16
+ }
@@ -8,7 +8,7 @@ import { isBuiltInAccent, siteAccent, siteAccentCss, siteAccentKey } from "./sha
8
8
  import { motionAllowed } from "../../motion/core.js";
9
9
  import { startPageTransition, viewTransitionsSupported } from "../../motion/page-transition.js";
10
10
  import { parseSiteHref, readSiteLocation, sitePageHref, writeSiteLocation } from "./shared/site-routing.js";
11
- const SiteShellContext = React.createContext(null);
11
+ const SiteShellContext = /*#__PURE__*/ React.createContext(null);
12
12
  /** Page, locale and navigation of the closest Site shell. Throws outside one. */
13
13
  export function useSiteShell() {
14
14
  const ctx = React.useContext(SiteShellContext);
@@ -34,7 +34,7 @@ export function useSiteShell() {
34
34
  * </SiteShell>
35
35
  * ```
36
36
  */
37
- export const SiteShell = React.forwardRef(function SiteShell({ accent, accentDark, font, material, density, theme, dir, locales = ["en", "tr"], locale: localeProp, defaultLocale, onLocaleChange, pages = ["home"], page: pageProp, defaultPage, onPageChange, routing = "search", pageParam = "page", localeParam = "lang", motion = "subtle", className, onClick, children, ...props }, ref) {
37
+ export const SiteShell = /*#__PURE__*/ React.forwardRef(function SiteShell({ accent, accentDark, font, material, density, theme, dir, locales = ["en", "tr"], locale: localeProp, defaultLocale, onLocaleChange, pages = ["home"], page: pageProp, defaultPage, onPageChange, routing = "search", pageParam = "page", localeParam = "lang", motion = "subtle", className, onClick, children, ...props }, ref) {
38
38
  const homeLocale = defaultLocale ?? locales[0] ?? "en";
39
39
  const homePage = defaultPage ?? pages[0] ?? "home";
40
40
  const [locale, setLocale] = useControllableState({ value: localeProp, defaultValue: homeLocale, onChange: onLocaleChange, name: "SiteShell" });
@@ -248,7 +248,7 @@ export function SiteShellLocale({ code, children }) {
248
248
  * A link to an inner page for client code. Server components can use a plain
249
249
  * `href={sitePageHref("pricing")}` instead; the shell handles both.
250
250
  */
251
- export const SiteShellLink = React.forwardRef(function SiteShellLink({ page, anchor, ...props }, ref) {
251
+ export const SiteShellLink = /*#__PURE__*/ React.forwardRef(function SiteShellLink({ page, anchor, ...props }, ref) {
252
252
  const { hrefFor, page: current } = useSiteShell();
253
253
  return _jsx("a", { ref: ref, href: hrefFor(page, anchor), "aria-current": !anchor && current === page ? "page" : undefined, ...props });
254
254
  });
@@ -11,7 +11,7 @@ export interface TeamMember {
11
11
  role: React.ReactNode;
12
12
  /** Specialty line in `list` ("Deep tissue · Sports massage"). */
13
13
  specialty?: React.ReactNode;
14
- /** 4:5 portrait. No photo = an empty inset area, never initials. */
14
+ /** 4:5 portrait. No photo = an empty inset area, never initials. `sizes`: grid `min(25vw, 19rem)` / 50vw · rows 56px · feature `min(42vw, 32rem)` / 100vw · compact 160px. */
15
15
  photo?: SiteImage2;
16
16
  bio?: React.ReactNode;
17
17
  /** Up to 3 profile links, rendered as short text links ("LinkedIn"). */
@@ -7,6 +7,7 @@ import { BlockLink } from "../block-link.js";
7
7
  import { site2Text } from "./shared/labels-2.js";
8
8
  import { fieldAttr, textOf, useBlockIds2 } from "./shared/kit-2.js";
9
9
  import { BRAND_NAMES } from "./shared/brand-icons.js";
10
+ import { columnSizes } from "./shared/image-sizes.js";
10
11
  /**
11
12
  * Team and specialist introduction — spa therapists, clinic doctors, an agency team. Card-less
12
13
  * by default (D6-1). Server component; the hover portrait in `list` is CSS only.
@@ -30,7 +31,7 @@ function ProfileLinks({ member, ctx, className }) {
30
31
  if (!member.links?.length)
31
32
  return null;
32
33
  const name = textOf(member.name);
33
- return (_jsx("span", { className: cn("flex flex-wrap gap-x-3 gap-y-1", className), children: member.links.slice(0, 3).map((l, i) => (_jsx(BlockLink, { href: l.href, newTab: true, components: ctx.components, labels: ctx.labels, locale: ctx.locale, "aria-label": name ? ctx.t("profileOf", { name, network: BRAND_NAMES[l.network] }) : undefined, className: "relative z-10 text-small text-fg-muted underline decoration-line underline-offset-[0.25em] transition-colors hover:text-fg hover:decoration-current focus-ring rounded-[2px]", children: BRAND_NAMES[l.network] }, i))) }));
34
+ return (_jsx("span", { className: cn("flex flex-wrap gap-x-3 gap-y-1 pointer-coarse:gap-y-0", className), children: member.links.slice(0, 3).map((l, i) => (_jsx(BlockLink, { href: l.href, newTab: true, components: ctx.components, labels: ctx.labels, locale: ctx.locale, "aria-label": name ? ctx.t("profileOf", { name, network: BRAND_NAMES[l.network] }) : undefined, className: "relative z-10 inline-flex min-h-6 items-center pointer-coarse:min-h-11 text-small text-fg-muted underline decoration-line underline-offset-[0.25em] transition-colors hover:text-fg hover:decoration-current focus-ring rounded-[2px]", children: BRAND_NAMES[l.network] }, i))) }));
34
35
  }
35
36
  function Portrait({ photo, ctx, className, sizes }) {
36
37
  if (!photo?.src)
@@ -38,11 +39,11 @@ function Portrait({ photo, ctx, className, sizes }) {
38
39
  return _jsx(BlockImage, { ...photo, alt: photo.alt ?? "", decorative: !photo.alt, aspect: "4:5", sizes: sizes, className: cn("rounded-ui", className), components: ctx.components });
39
40
  }
40
41
  function PortraitMember({ member, index, ctx }) {
41
- return (_jsxs("li", { className: "flex flex-col gap-4", children: [_jsx(Portrait, { photo: member.photo, ctx: ctx, sizes: "(min-width: 56rem) 25vw, 50vw" }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsxs("div", { className: "flex flex-wrap items-baseline justify-between gap-x-3 gap-y-1", children: [_jsx("h3", { className: "text-h3 font-semibold tracking-[-0.012em] text-fg", ...fieldAttr(ctx.editMode, `members.${index}.name`), children: _jsx(DisplayName, { member: member }) }), _jsx(ProfileLinks, { member: member, ctx: ctx })] }), _jsx("p", { className: "font-mono text-eyebrow uppercase tracking-[0.06em] text-fg-muted", children: member.role }), member.bio ? _jsx("p", { className: "mt-2 text-small text-fg-muted text-pretty", children: member.bio }) : null] })] }));
42
+ return (_jsxs("li", { className: "flex flex-col gap-4", children: [_jsx(Portrait, { photo: member.photo, ctx: ctx, sizes: columnSizes(1 / 4, { narrow: "50vw" }) }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsxs("div", { className: "flex flex-wrap items-baseline justify-between gap-x-3 gap-y-1", children: [_jsx("h3", { className: "text-h3 font-semibold tracking-[-0.012em] text-fg", ...fieldAttr(ctx.editMode, `members.${index}.name`), children: _jsx(DisplayName, { member: member }) }), _jsx(ProfileLinks, { member: member, ctx: ctx })] }), _jsx("p", { className: "font-mono text-eyebrow uppercase tracking-[0.06em] text-fg-muted", children: member.role }), member.bio ? _jsx("p", { className: "mt-2 text-small text-fg-muted text-pretty", children: member.bio }) : null] })] }));
42
43
  }
43
44
  function ListMember({ member, index, ctx }) {
44
45
  return (_jsxs("li", { className: "vb-team-row group/row relative grid grid-cols-[3.5rem_1fr] items-center gap-x-4 gap-y-1 border-t border-line py-6 @2xl:grid-cols-12 @2xl:gap-x-(--gutter)", children: [_jsx("span", { className: "row-span-2 @2xl:hidden", children: _jsx(Portrait, { photo: member.photo, ctx: ctx, className: "w-14 rounded-ui-sm", sizes: "56px" }) }), _jsx("h3", { className: "text-h3 font-semibold tracking-[-0.012em] text-fg @2xl:col-span-4", ...fieldAttr(ctx.editMode, `members.${index}.name`), children: _jsx(DisplayName, { member: member }) }), _jsx("p", { className: "font-mono text-eyebrow uppercase tracking-[0.06em] text-fg-muted @2xl:col-span-3", children: member.role }), _jsxs("div", { className: "col-start-2 flex flex-wrap items-baseline gap-x-6 gap-y-1 @2xl:col-span-5 @2xl:col-start-auto @2xl:justify-between", children: [member.specialty ? _jsx("p", { className: "text-small text-fg-muted", children: member.specialty }) : _jsx("span", {}), _jsx(ProfileLinks, { member: member, ctx: ctx })] }), member.photo?.src ? (_jsx("span", { "aria-hidden": true, className: "vb-team-hover pointer-events-none absolute end-[22%] top-1/2 z-10 hidden w-40 -translate-y-1/2 @4xl:block", children: _jsx(BlockImage, { ...member.photo, decorative: true, aspect: "4:5", sizes: "160px", className: "rounded-ui", components: ctx.components }) })) : null] }));
45
46
  }
46
47
  function FeatureMember({ member, header, ctx }) {
47
- return (_jsxs("div", { className: "grid gap-x-(--gutter) gap-y-10 @4xl:grid-cols-12 @4xl:items-start", children: [_jsx("div", { className: "@4xl:col-span-5", children: _jsx(Portrait, { photo: member.photo, ctx: ctx, sizes: "(min-width: 56rem) 40vw, 100vw" }) }), _jsxs("div", { className: "flex flex-col gap-8 @4xl:col-span-6 @4xl:col-start-7 @4xl:pt-6", children: [header, member.bio ? _jsx("div", { className: "text-lead text-fg-muted text-pretty [&_p+p]:mt-4", children: typeof member.bio === "string" ? member.bio.split(/\n{2,}/).map((p, i) => _jsx("p", { children: p }, i)) : member.bio }) : null, _jsxs("div", { className: "flex flex-col gap-2 border-t border-line pt-6", children: [_jsx("p", { className: "vb-signature font-display text-display-m italic text-fg", ...fieldAttr(ctx.editMode, "members.0.name"), children: _jsx(DisplayName, { member: member }) }), _jsx("p", { className: "font-mono text-eyebrow uppercase tracking-[0.06em] text-fg-muted", children: member.role }), _jsx(ProfileLinks, { member: member, ctx: ctx, className: "mt-2" })] })] })] }));
48
+ return (_jsxs("div", { className: "grid gap-x-(--gutter) gap-y-10 @4xl:grid-cols-12 @4xl:items-start", children: [_jsx("div", { className: "@4xl:col-span-5", children: _jsx(Portrait, { photo: member.photo, ctx: ctx, sizes: columnSizes(5 / 12) }) }), _jsxs("div", { className: "flex flex-col gap-8 @4xl:col-span-6 @4xl:col-start-7 @4xl:pt-6", children: [header, member.bio ? _jsx("div", { className: "text-lead text-fg-muted text-pretty [&_p+p]:mt-4", children: typeof member.bio === "string" ? member.bio.split(/\n{2,}/).map((p, i) => _jsx("p", { children: p }, i)) : member.bio }) : null, _jsxs("div", { className: "flex flex-col gap-2 border-t border-line pt-6", children: [_jsx("p", { className: "vb-signature font-display text-display-m italic text-fg", ...fieldAttr(ctx.editMode, "members.0.name"), children: _jsx(DisplayName, { member: member }) }), _jsx("p", { className: "font-mono text-eyebrow uppercase tracking-[0.06em] text-fg-muted", children: member.role }), _jsx(ProfileLinks, { member: member, ctx: ctx, className: "mt-2" })] })] })] }));
48
49
  }
@@ -10,9 +10,9 @@ export interface TestimonialItem {
10
10
  author: React.ReactNode;
11
11
  role?: React.ReactNode;
12
12
  company?: React.ReactNode;
13
- /** Small square portrait. No avatar = name only (never an initials circle). */
13
+ /** Small round portrait, 40px (`sizes="40px"`). No avatar = name only (never an initials circle). */
14
14
  avatar?: SiteImage2;
15
- /** Company logo (feature variant). */
15
+ /** Company logo (feature variant), 6rem wide (`sizes="6rem"`). */
16
16
  logo?: SiteImage2;
17
17
  /** 1–5. Rendered only with a `source` (D6-8). */
18
18
  rating?: number;
@@ -42,14 +42,14 @@ export function RatingStars({ rating, label, size = "md", className }) {
42
42
  }
43
43
  function Attribution({ item, ctx, align = "start", as: Comp = "figcaption" }) {
44
44
  const meta = [item.role, item.company].filter(Boolean);
45
- return (_jsxs(Comp, { className: cn("flex items-center gap-3", align === "between" && "justify-between"), children: [_jsxs("span", { className: "flex items-center gap-3", children: [item.avatar ? (_jsx(BlockImage, { ...item.avatar, alt: item.avatar.alt ?? "", decorative: !item.avatar.alt, aspect: "1:1", sizes: "40px", className: "size-10 shrink-0 rounded-full", components: ctx.components })) : null, _jsxs("span", { className: "flex flex-col", children: [_jsx("span", { className: "text-sm font-medium text-fg", children: item.author }), meta.length ? (_jsx("span", { className: "font-mono text-eyebrow uppercase tracking-[0.06em] text-fg-muted", children: meta.map((m, i) => (_jsxs(React.Fragment, { children: [i > 0 ? " · " : null, m] }, i))) })) : null] })] }), align === "between" && item.logo ? (_jsx(BlockImage, { ...item.logo, alt: item.logo.alt ?? "", decorative: !item.logo.alt, fit: "contain", className: "h-7 w-24 bg-transparent opacity-80", imgClassName: "vb-logo-mono", components: ctx.components })) : null] }));
45
+ return (_jsxs(Comp, { className: cn("flex items-center gap-3", align === "between" && "justify-between"), children: [_jsxs("span", { className: "flex items-center gap-3", children: [item.avatar ? (_jsx(BlockImage, { ...item.avatar, alt: item.avatar.alt ?? "", decorative: !item.avatar.alt, aspect: "1:1", sizes: "40px", className: "size-10 shrink-0 rounded-full", components: ctx.components })) : null, _jsxs("span", { className: "flex flex-col", children: [_jsx("span", { className: "text-sm font-medium text-fg", children: item.author }), meta.length ? (_jsx("span", { className: "font-mono text-eyebrow uppercase tracking-[0.06em] text-fg-muted", children: meta.map((m, i) => (_jsxs(React.Fragment, { children: [i > 0 ? " · " : null, m] }, i))) })) : null] })] }), align === "between" && item.logo ? (_jsx(BlockImage, { ...item.logo, alt: item.logo.alt ?? "", decorative: !item.logo.alt, fit: "contain", sizes: "6rem", className: "h-7 w-24 bg-transparent opacity-80", imgClassName: "vb-logo-mono", components: ctx.components })) : null] }));
46
46
  }
47
47
  function SourceLine({ item, ctx }) {
48
48
  const showRating = item.rating !== undefined && item.source;
49
49
  const name = item.source ? REVIEW_SOURCE_NAMES[item.source] : "";
50
50
  if (!showRating && !item.date && !name)
51
51
  return null;
52
- return (_jsxs("p", { className: "flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-fg-muted", children: [showRating ? _jsx(RatingStars, { rating: item.rating, label: ctx.t("ratingOutOf", { rating: item.rating }) }) : null, name ? (item.link ? (_jsx(BlockLink, { href: item.link.href, newTab: item.link.newTab ?? true, components: ctx.components, labels: ctx.labels, locale: ctx.locale, className: "underline decoration-line underline-offset-[0.25em] hover:decoration-current focus-ring rounded-[2px]", children: name })) : (_jsx("span", { children: name }))) : null, item.date ? _jsx("time", { dateTime: isoDay(item.date), children: formatDate2(isoDay(item.date), ctx.locale, "medium") }) : null] }));
52
+ return (_jsxs("p", { className: "flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-fg-muted", children: [showRating ? _jsx(RatingStars, { rating: item.rating, label: ctx.t("ratingOutOf", { rating: item.rating }) }) : null, name ? (item.link ? (_jsx(BlockLink, { href: item.link.href, newTab: item.link.newTab ?? true, components: ctx.components, labels: ctx.labels, locale: ctx.locale, className: "inline-flex min-h-6 items-center underline decoration-line underline-offset-[0.25em] hover:decoration-current focus-ring rounded-[2px]", children: name })) : (_jsx("span", { children: name }))) : null, item.date ? _jsx("time", { dateTime: isoDay(item.date), children: formatDate2(isoDay(item.date), ctx.locale, "medium") }) : null] }));
53
53
  }
54
54
  function QuoteFigure({ item, index, ctx, size = "s" }) {
55
55
  return (_jsxs("figure", { className: "flex flex-col gap-5", children: [_jsx(SourceLine, { item: item, ctx: ctx }), _jsx("blockquote", { className: cn("text-fg text-pretty", size === "m" ? "text-lead" : "text-body"), ...fieldAttr(ctx.editMode, `items.${index}.quote`), children: _jsxs("p", { children: [_jsx("span", { "aria-hidden": true, children: ctx.t("quoteOpen") }), item.quote, _jsx("span", { "aria-hidden": true, children: ctx.t("quoteClose") })] }) }), _jsx(Attribution, { item: item, ctx: ctx })] }));
@@ -62,5 +62,5 @@ function ReviewsLayout({ header, items, summary, ctx }) {
62
62
  const sourceName = summary ? REVIEW_SOURCE_NAMES[summary.source] : "";
63
63
  return (_jsxs("div", { className: "grid gap-x-(--gutter) gap-y-12 @4xl:grid-cols-12", children: [_jsxs("div", { className: "flex flex-col gap-8 @4xl:sticky @4xl:top-[calc(var(--topbar-h,0px)+2rem)] @4xl:col-span-4 @4xl:self-start", children: [header, summary ? (_jsxs("div", { className: "flex flex-col gap-3 border-t border-line pt-6", children: [_jsxs("p", { className: "flex items-baseline gap-3", children: [_jsx("span", { className: "font-display text-display-l tabular text-fg", children: nf.number(summary.rating, { minimumFractionDigits: 1, maximumFractionDigits: 1 }) }), _jsx(RatingStars, { rating: summary.rating, label: ctx.t("ratingOutOf", { rating: nf.number(summary.rating, { maximumFractionDigits: 1 }) }) })] }), _jsxs("p", { className: "text-small text-fg-muted", children: [sourceName
64
64
  ? ctx.t("ratingSummary", { rating: nf.number(summary.rating, { maximumFractionDigits: 1 }), source: sourceName })
65
- : ctx.t("ratingSummaryDirect", { rating: nf.number(summary.rating, { maximumFractionDigits: 1 }) }), " ", "\u2014 ", ctx.t("reviewCount", { count: summary.count })] }), summary.link ? (_jsx(BlockLink, { href: summary.link.href, newTab: summary.link.newTab ?? true, appearance: "link", components: ctx.components, labels: ctx.labels, locale: ctx.locale, className: "self-start text-small", children: summary.link.label ?? ctx.t("readAllReviews") })) : null] })) : null] }), _jsx("ol", { className: "flex flex-col @4xl:col-span-7 @4xl:col-start-6", children: items.map((item, i) => (_jsx("li", { className: "border-t border-line py-7 first:border-t-0 first:pt-0 @4xl:first:border-t @4xl:first:pt-7", children: _jsx(QuoteFigure, { item: item, index: i, ctx: ctx }) }, i))) })] }));
65
+ : ctx.t("ratingSummaryDirect", { rating: nf.number(summary.rating, { maximumFractionDigits: 1 }) }), " ", "\u2014 ", ctx.t("reviewCount", { count: summary.count })] }), summary.link ? (_jsx(BlockLink, { href: summary.link.href, newTab: summary.link.newTab ?? true, appearance: "link", components: ctx.components, labels: ctx.labels, locale: ctx.locale, className: "inline-flex min-h-6 items-center self-start text-small", children: summary.link.label ?? ctx.t("readAllReviews") })) : null] })) : null] }), _jsx("ol", { className: "flex flex-col @4xl:col-span-7 @4xl:col-start-6", children: items.map((item, i) => (_jsx("li", { className: "border-t border-line py-7 first:border-t-0 first:pt-0 @4xl:first:border-t @4xl:first:pt-7", children: _jsx(QuoteFigure, { item: item, index: i, ctx: ctx }) }, i))) })] }));
66
66
  }
@@ -110,7 +110,7 @@ function groupStatus(g) {
110
110
  * <ApprovalFlow requester={{ name: "Deniz Aydın", at: "2026-11-03T09:12:00Z" }} stages={stages} />
111
111
  * ```
112
112
  */
113
- export const ApprovalFlow = React.forwardRef(function ApprovalFlow({ stages, requester, orientation = "vertical", variant = "full", now, labels, className, ...props }, ref) {
113
+ export const ApprovalFlow = /*#__PURE__*/ React.forwardRef(function ApprovalFlow({ stages, requester, orientation = "vertical", variant = "full", now, labels, className, ...props }, ref) {
114
114
  const t = useLabels("approvalFlow", approvalFlowLabels, labels);
115
115
  if (variant === "compact")
116
116
  return _jsx(ApprovalSummary, { stages: stages, labels: labels, className: className });
@@ -153,7 +153,7 @@ function ApproverRow({ approver: a, t, stageActive }) {
153
153
  return (_jsxs("li", { className: "flex min-w-0 gap-2.5", "data-slot": "approval-approver", "data-decision": d?.value, children: [_jsx(Avatar, { name: a.name, src: a.avatarUrl, size: "sm" }), _jsxs("div", { className: "min-w-0 flex-1 text-[13px] leading-snug", children: [_jsxs("p", { className: "flex flex-wrap items-baseline gap-x-1.5", children: [_jsx("span", { className: "font-medium text-fg", children: a.name }), a.role ? _jsx("span", { className: "text-xs text-fg-subtle", children: a.role }) : null, d?.delegatedFrom ? (_jsxs(Badge, { tone: "info", size: "sm", children: [_jsx(Forward, {}), " ", t("delegated")] })) : null] }), d ? (_jsxs("p", { className: "mt-0.5 text-xs text-fg-muted", children: [_jsx("span", { className: cn("font-medium", decisionTone), children: decisionWord(t, d.value) }), " ", _jsx("time", { dateTime: d.at, className: "tabular", children: format.dateTime(d.at, { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" }) }), d.delegatedFrom ? _jsxs(_Fragment, { children: [" \u00B7 ", t("delegatedFrom", { name: d.delegatedFrom.name })] }) : null] })) : (_jsx("p", { className: "mt-0.5 text-xs text-fg-subtle", children: stageActive ? t("pending") : "—" })), d?.note ? (_jsx("blockquote", { className: "mt-1.5 rounded-ui-sm border-s-2 border-(--q) bg-surface-2 px-2.5 py-1.5 text-[13px] text-fg [--q:var(--line)] data-[v=rejected]:[--q:var(--danger)] data-[v=changes_requested]:[--q:var(--warning)]", "data-v": d.value, children: d.note })) : null] })] }));
154
154
  }
155
155
  /** Inline status for table rows: one dot per stage + "2 of 3 approved". */
156
- export const ApprovalSummary = React.forwardRef(function ApprovalSummary({ stages, showCurrent = true, labels, className, ...props }, ref) {
156
+ export const ApprovalSummary = /*#__PURE__*/ React.forwardRef(function ApprovalSummary({ stages, showCurrent = true, labels, className, ...props }, ref) {
157
157
  const t = useLabels("approvalFlow", approvalFlowLabels, labels);
158
158
  const counted = stages.filter((s) => s.status !== "skipped");
159
159
  const done = counted.filter((s) => s.status === "approved").length;
@@ -111,7 +111,7 @@ const DEFAULT_LOCALES = [
111
111
  * <ImportWizard fields={contactFields} dedupeKeys={["email"]} onImport={(rows, { signal }) => api.contacts.bulk(rows, { signal })} />
112
112
  * ```
113
113
  */
114
- export const ImportWizard = React.forwardRef(function ImportWizard({ fields, dedupeKeys, maxRows = 50_000, maxSize = 20 * 1024 * 1024, chunkSize = 200, onImport, templates, sampleFile, fileLocales, onDone, previewLimit = 200, labels, className, ...props }, ref) {
114
+ export const ImportWizard = /*#__PURE__*/ React.forwardRef(function ImportWizard({ fields, dedupeKeys, maxRows = 50_000, maxSize = 20 * 1024 * 1024, chunkSize = 200, onImport, templates, sampleFile, fileLocales, onDone, previewLimit = 200, labels, className, ...props }, ref) {
115
115
  const t = useLabels("importWizard", importWizardLabels, labels);
116
116
  const { locale, format } = useLocale();
117
117
  const [step, setStep] = React.useState("upload");
@@ -278,7 +278,7 @@ function LineItemsInner(props, ref) {
278
278
  * <LineItems currency="TRY" taxPack={trLineTaxPack()} units={["hour", "day", "pcs"]} defaultValue={rows} onValueChange={(rows, totals) => save(rows, totals.payable)} />
279
279
  * ```
280
280
  */
281
- export const LineItems = React.forwardRef(LineItemsInner);
281
+ export const LineItems = /*#__PURE__*/ React.forwardRef(LineItemsInner);
282
282
  /* ------------------------------------------------------------------ */
283
283
  /* Summary */
284
284
  /* ------------------------------------------------------------------ */
@@ -28,7 +28,7 @@ export const multiStepFormLabels = {
28
28
  review: "Review",
29
29
  leave: "You have unsaved changes. Leave anyway?",
30
30
  };
31
- const MultiStepFormContext = React.createContext(null);
31
+ const MultiStepFormContext = /*#__PURE__*/ React.createContext(null);
32
32
  function useCtx(part) {
33
33
  const ctx = React.useContext(MultiStepFormContext);
34
34
  if (!ctx)
@@ -262,7 +262,7 @@ function MultiStepFormInner(props, ref) {
262
262
  * </MultiStepForm>
263
263
  * ```
264
264
  */
265
- export const MultiStepForm = React.forwardRef(MultiStepFormInner);
265
+ export const MultiStepForm = /*#__PURE__*/ React.forwardRef(MultiStepFormInner);
266
266
  /** The progress display (kit `Stepper`), wired to the form: completed steps are clickable. */
267
267
  export function MultiStepFormStepper({ variant = "numbered", className }) {
268
268
  const c = useCtx("MultiStepFormStepper");
@@ -67,7 +67,7 @@ const levelLabel = (t, v, scoped, scopeNames) => {
67
67
  * inherited={manager} inheritedFrom="Manager" baseline={saved} onSave={save} dependencies={[{ action: "edit", requires: "view" }]} />
68
68
  * ```
69
69
  */
70
- export const PermissionMatrix = React.forwardRef(function PermissionMatrix({ resources, actions, scopes, value: valueProp, defaultValue, onValueChange, inherited, inheritedFrom = "parent role", baseline, onSave, subject = "this role", readOnly, dependencies, onDependencyApplied, maxHeight, labels, className, ...props }, ref) {
70
+ export const PermissionMatrix = /*#__PURE__*/ React.forwardRef(function PermissionMatrix({ resources, actions, scopes, value: valueProp, defaultValue, onValueChange, inherited, inheritedFrom = "parent role", baseline, onSave, subject = "this role", readOnly, dependencies, onDependencyApplied, maxHeight, labels, className, ...props }, ref) {
71
71
  const t = useLabels("permissionMatrix", permissionMatrixLabels, labels);
72
72
  const [value, setValueState] = useControllableState({ value: valueProp, defaultValue: defaultValue ?? {} });
73
73
  const [collapsed, setCollapsed] = React.useState(() => new Set());
@@ -44,7 +44,7 @@ function counts(items) {
44
44
  * {hidden ? <SetupChecklistLauncher items={steps} onOpen={() => setHidden(false)} /> : null}
45
45
  * ```
46
46
  */
47
- export const SetupChecklist = React.forwardRef(function SetupChecklist({ title, description, items, onSkip, onUndoSkip, dismissed, onDismissedChange, variant = "card", expandFirstIncomplete = true, onAllDone, loading, labels, className, ...props }, ref) {
47
+ export const SetupChecklist = /*#__PURE__*/ React.forwardRef(function SetupChecklist({ title, description, items, onSkip, onUndoSkip, dismissed, onDismissedChange, variant = "card", expandFirstIncomplete = true, onAllDone, loading, labels, className, ...props }, ref) {
48
48
  const t = useLabels("setupChecklist", setupChecklistLabels, labels);
49
49
  const { done, total, allDone } = counts(items);
50
50
  const firstOpen = items.find((i) => (i.status === "todo" || i.status === "in_progress") && !i.locked)?.id;
@@ -85,7 +85,7 @@ function SetupChecklistItem({ item, index, open, current, onToggle, onSkip, onUn
85
85
  return (_jsxs("li", { "data-slot": "setup-checklist-item", "data-status": item.status, "data-current": current && !finished ? "" : undefined, className: cn("vui-setup-item rounded-ui transition-colors", current && !finished && !compact && "bg-accent-soft/50"), children: [_jsx("h3", { className: "m-0 text-inherit font-normal", children: _jsxs("button", { type: "button", "aria-expanded": hasDetails ? open : undefined, "aria-controls": hasDetails ? panelId : undefined, onClick: hasDetails ? onToggle : undefined, className: cn("focus-ring flex w-full items-center gap-3 rounded-ui text-start", compact ? "px-1 py-1.5" : "px-2.5 py-2.5", hasDetails && "hover:bg-hover"), children: [_jsx(StatusMark, { status: item.status, locked: locked, index: index }), _jsxs("span", { className: cn("min-w-0 flex-1 text-sm", finished ? "text-fg-muted" : "text-fg", item.status === "done" && "line-through decoration-fg-subtle/60", item.status === "skipped" && "italic"), children: [item.title, _jsxs("span", { className: "sr-only", children: [", ", statusText] })] }), item.optional && !finished ? _jsx("span", { className: "text-[11px] text-fg-subtle", children: t("optional") }) : null, item.estimate && !finished && !compact ? _jsx("span", { className: "font-mono text-[11px] text-fg-subtle tabular", children: item.estimate }) : null, hasDetails ? _jsx(ChevronDown, { "aria-hidden": true, className: cn("size-4 shrink-0 text-fg-subtle transition-transform duration-200", open && "rotate-180") }) : null] }) }), hasDetails ? (_jsxs("div", { id: panelId, hidden: !open, className: cn("vui-setup-panel", compact ? "ps-8 pb-2" : "ps-[2.875rem] pe-3 pb-3"), children: [item.description ? _jsx("p", { className: "text-[13px] text-fg-muted", children: item.description }) : null, locked ? (_jsxs("p", { className: "mt-1.5 flex items-center gap-1.5 text-xs text-fg-subtle", children: [_jsx(Lock, { "aria-hidden": true, className: "size-3" }), " ", item.locked.reason] })) : null, _jsxs("div", { className: "mt-2.5 flex flex-wrap items-center gap-2 empty:hidden", children: [item.action && !finished ? (item.action.href ? (_jsx(Button, { asChild: true, size: "sm", variant: current ? "primary" : "secondary", disabled: locked, children: _jsxs(SmartLink, { href: item.action.href, children: [item.action.label, " ", _jsx(ArrowRight, { className: "rtl:rotate-180" })] }) })) : (_jsxs(Button, { size: "sm", variant: current ? "primary" : "secondary", disabled: locked, onClick: item.action.onSelect, children: [item.action.label, " ", _jsx(ArrowRight, { className: "rtl:rotate-180" })] }))) : null, !finished && onSkip ? (_jsx(Button, { size: "sm", variant: "ghost", onClick: () => onSkip(item.id), children: t("skip") })) : null, item.status === "skipped" && onUndoSkip ? (_jsxs(Button, { size: "sm", variant: "ghost", onClick: () => onUndoSkip(item.id), children: [_jsx(Undo2, {}), " ", t("undoSkip")] })) : null] })] })) : null] }));
86
86
  }
87
87
  /** A pill that reopens a dismissed checklist: "Setup guide · 3 of 6". */
88
- export const SetupChecklistLauncher = React.forwardRef(function SetupChecklistLauncher({ items, onOpen, floating, labels, className, ...props }, ref) {
88
+ export const SetupChecklistLauncher = /*#__PURE__*/ React.forwardRef(function SetupChecklistLauncher({ items, onOpen, floating, labels, className, ...props }, ref) {
89
89
  const t = useLabels("setupChecklist", setupChecklistLabels, labels);
90
90
  const { done, total } = counts(items);
91
91
  return (_jsxs("button", { ref: ref, type: "button", "data-slot": "setup-checklist-launcher", onClick: onOpen, className: cn("focus-ring inline-flex h-9 items-center gap-2 rounded-full surface-popover ps-1.5 pe-3.5 text-[13px] font-medium text-fg transition-[transform,box-shadow] duration-150 motion-safe:hover:-translate-y-px", floating && "fixed end-5 bottom-5 z-40", className), ...props, children: [_jsx(ProgressCircle, { value: total ? (done / total) * 100 : 0, size: "sm", "aria-hidden": true, className: "size-6" }), t("reopen", { done, total })] }));
@@ -44,7 +44,7 @@ const stateTone = {
44
44
  * <SignerStatus sequential signers={contract.signers} onRemind={(s) => api.remind(s.id)} />
45
45
  * ```
46
46
  */
47
- export const SignerStatus = React.forwardRef(function SignerStatus({ signers, sequential, title, onRemind, now, labels, className, ...props }, ref) {
47
+ export const SignerStatus = /*#__PURE__*/ React.forwardRef(function SignerStatus({ signers, sequential, title, onRemind, now, labels, className, ...props }, ref) {
48
48
  const t = useLabels("signerStatus", signerStatusLabels, labels);
49
49
  const f = useFormat();
50
50
  const titleId = React.useId();
@@ -14,7 +14,7 @@ import { estimateAxisWidth, extent, formatValue, seriesColor } from "./utils.js"
14
14
  * ```
15
15
  */
16
16
  export function BarChart({ series, layout = "vertical", stack = "none", radius = 4, highlight, valueLabels, barSize = "auto", reference, ...props }) {
17
- return (_jsx(Chart, { skeleton: layout === "horizontal" ? "bar-horizontal" : "bar", ...props, children: _jsx(BarPlot, { series: series, layout: layout, stack: stack, radius: radius, highlight: highlight, valueLabels: valueLabels, barSize: barSize, reference: reference }) }));
17
+ return (_jsx(Chart, { skeleton: layout === "horizontal" ? "bar-horizontal" : "bar", barKeys: series ?? Object.keys(props.config), ...props, children: _jsx(BarPlot, { series: series, layout: layout, stack: stack, radius: radius, highlight: highlight, valueLabels: valueLabels, barSize: barSize, reference: reference }) }));
18
18
  }
19
19
  function BarPlot({ series: keys, layout, stack, radius = 4, highlight, valueLabels, barSize, reference }) {
20
20
  const chart = useChart();
@@ -18,7 +18,7 @@ const textOf = (item) => item.textLabel ?? (typeof item.label === "string" ? ite
18
18
  * <BarList aria-label="Top sources" data={[{ key: "google", label: "Google", value: 4120 }]} showShare />
19
19
  * ```
20
20
  */
21
- export const BarList = React.forwardRef(function BarList({ data, format = "number", color, max, sort = "desc", showShare, onItemClick, size = "md", variant = "filled", loading, loadingRows = 5, emptyMessage, labels, className, ...props }, ref) {
21
+ export const BarList = /*#__PURE__*/ React.forwardRef(function BarList({ data, format = "number", color, max, sort = "desc", showShare, onItemClick, size = "md", variant = "filled", loading, loadingRows = 5, emptyMessage, labels, className, ...props }, ref) {
22
22
  const f = useFormat();
23
23
  const { locale } = useLocale();
24
24
  const t = useLabels("chart", chartLabels, labels);
@@ -59,6 +59,8 @@ export interface ChartContextValue {
59
59
  onPointClick?: (row: Row, seriesKey: string) => void;
60
60
  height: number | undefined;
61
61
  idPrefix: string;
62
+ /** Series drawn as bars: no stroke pattern, so their legend and tooltip swatch is a solid square. */
63
+ isBar: (key: string) => boolean;
62
64
  }
63
65
  /** Chart context: config, formatters and hidden series. Use inside `<Chart>`. */
64
66
  export declare function useChart(): ChartContextValue;
@@ -100,6 +102,11 @@ export interface ChartProps<T extends object = Row> extends Omit<React.HTMLAttri
100
102
  labels?: Partial<ChartLabels>;
101
103
  /** Replace the generated data table. */
102
104
  table?: ChartTableSpec;
105
+ /**
106
+ * Series drawn as bars. Bars carry no stroke pattern, so their legend and tooltip swatch is a
107
+ * solid square even when the other series get dashed/dotted lines. Bar and Combo charts set it.
108
+ */
109
+ barKeys?: string[];
103
110
  /** Content beside (or under) the plot — e.g. the Donut legend list. */
104
111
  aside?: React.ReactNode;
105
112
  asidePosition?: "side" | "bottom";
@@ -127,8 +134,8 @@ export interface ChartLegendContentProps extends React.HTMLAttributes<HTMLDivEle
127
134
  keys?: string[];
128
135
  /** Click toggles visibility. Default `true`. */
129
136
  interactive?: boolean;
130
- /** Swatch shape. Default: a line for line/area patterns, a dot otherwise. */
131
- swatch?: "dot" | "line";
137
+ /** Swatch shape. Default: a solid square for bar series, a line for line/area patterns, a dot otherwise. */
138
+ swatch?: "dot" | "line" | "square";
132
139
  }
133
140
  /** The legend: one toggle per series (`aria-pressed`). At least one series always stays visible. */
134
141
  export declare function ChartLegendContent({ keys, interactive, swatch, className, ...props }: ChartLegendContentProps): React.JSX.Element;
@@ -29,7 +29,7 @@ export const chartLabels = {
29
29
  range: "{from} – {to}.",
30
30
  seriesSummary: "{label}: low {min} ({minAt}), high {max} ({maxAt}), average {avg}.",
31
31
  };
32
- const ChartContext = React.createContext(null);
32
+ const ChartContext = /*#__PURE__*/ React.createContext(null);
33
33
  /** Chart context: config, formatters and hidden series. Use inside `<Chart>`. */
34
34
  export function useChart() {
35
35
  const ctx = React.useContext(ChartContext);
@@ -52,7 +52,7 @@ const capitalise = (s) => (s ? s[0].toUpperCase() + s.slice(1) : s);
52
52
  * ```
53
53
  */
54
54
  export function Chart(props) {
55
- const { data: dataProp, config, x, xLabel, xFormat, yFormat, height, aspect, state: stateProp, title, summary, tableToggle, legend, tooltipIndicator = "dot", animate = true, onPointClick, hiddenSeries, defaultHiddenSeries, onHiddenSeriesChange, labels, table, aside, asidePosition = "side", skeleton = "area", toolbar, className, style, children, ...rest } = props;
55
+ const { data: dataProp, config, x, xLabel, xFormat, yFormat, height, aspect, state: stateProp, title, summary, tableToggle, legend, tooltipIndicator = "dot", animate = true, onPointClick, hiddenSeries, defaultHiddenSeries, onHiddenSeriesChange, labels, table, aside, asidePosition = "side", skeleton = "area", toolbar, barKeys, className, style, children, ...rest } = props;
56
56
  const data = dataProp;
57
57
  const f = useFormat();
58
58
  const t = useLabels("chart", chartLabels, labels);
@@ -79,6 +79,9 @@ export function Chart(props) {
79
79
  const status = stateProp ?? (data.length === 0 ? { status: "empty" } : { status: "ready" });
80
80
  const [showTable, setShowTable] = React.useState(false);
81
81
  const seriesFormat = React.useCallback((key) => config[key]?.format, [config]);
82
+ const barKeySet = barKeys?.join("\u0000") ?? "";
83
+ // eslint-disable-next-line react-hooks/exhaustive-deps
84
+ const isBar = React.useCallback((key) => (barKeys ?? []).includes(key), [barKeySet]);
82
85
  const ctx = React.useMemo(() => ({
83
86
  config,
84
87
  series,
@@ -99,7 +102,8 @@ export function Chart(props) {
99
102
  onPointClick: onPointClick,
100
103
  height: height === "auto" ? undefined : typeof height === "string" ? CHART_HEIGHTS[height] : height,
101
104
  idPrefix,
102
- }), [config, series, visibleSeries, hiddenSet, toggleSeries, data, x, xFormat, yFormat, f, t, animate, reduced, tooltipIndicator, onPointClick, height, idPrefix, seriesFormat]);
105
+ isBar,
106
+ }), [config, series, visibleSeries, hiddenSet, toggleSeries, data, x, xFormat, yFormat, f, t, animate, reduced, tooltipIndicator, onPointClick, height, idPrefix, seriesFormat, isBar]);
103
107
  const vars = React.useMemo(() => {
104
108
  const out = {};
105
109
  for (const s of series)
@@ -149,19 +153,21 @@ export function Chart(props) {
149
153
  }
150
154
  /** The legend: one toggle per series (`aria-pressed`). At least one series always stays visible. */
151
155
  export function ChartLegendContent({ keys, interactive = true, swatch, className, ...props }) {
152
- const { series, isHidden, toggleSeries, visibleSeries, t } = useChart();
156
+ const { series, isHidden, toggleSeries, visibleSeries, t, isBar } = useChart();
153
157
  const items = keys ? series.filter((s) => keys.includes(s.key)) : series;
154
158
  return (_jsx("div", { role: "group", "aria-label": t("legend"), "data-slot": "chart-legend", className: cn("flex flex-wrap items-center gap-x-1 gap-y-1", className), ...props, children: items.map((s) => {
155
159
  const hidden = isHidden(s.key);
156
160
  const locked = !hidden && visibleSeries.length <= 1;
157
161
  const Icon = s.icon;
158
- const content = (_jsxs(_Fragment, { children: [Icon ? _jsx(Icon, { className: "size-3.5" }) : _jsx(LegendSwatch, { color: seriesColor(s.key), pattern: s.pattern, shape: swatch ?? (s.pattern !== "solid" ? "line" : "dot") }), _jsx("span", { className: cn(hidden && "line-through decoration-fg-subtle"), children: s.label })] }));
162
+ const content = (_jsxs(_Fragment, { children: [Icon ? _jsx(Icon, { className: "size-3.5" }) : _jsx(LegendSwatch, { color: seriesColor(s.key), pattern: s.pattern, shape: swatch ?? (isBar(s.key) ? "square" : s.pattern !== "solid" ? "line" : "dot") }), _jsx("span", { className: cn(hidden && "line-through decoration-fg-subtle"), children: s.label })] }));
159
163
  if (!interactive)
160
164
  return (_jsx("span", { className: "inline-flex items-center gap-1.5 px-1.5 text-[12.5px] text-fg-muted", children: content }, s.key));
161
165
  return (_jsx("button", { type: "button", "aria-pressed": !hidden, "aria-disabled": locked || undefined, onClick: () => toggleSeries(s.key), className: cn("inline-flex h-7 items-center gap-1.5 rounded-ui-sm px-2 text-[12.5px] text-fg-muted transition-[color,background-color,opacity] focus-ring hover:bg-hover hover:text-fg", hidden && "opacity-55", locked && "cursor-default hover:bg-transparent"), children: content }, s.key));
162
166
  }) }));
163
167
  }
164
168
  function LegendSwatch({ color, pattern, shape }) {
169
+ if (shape === "square")
170
+ return _jsx("span", { "aria-hidden": true, "data-swatch": "square", className: "size-2.5 shrink-0 rounded-[2px]", style: { background: color } });
165
171
  if (shape === "line")
166
172
  return (_jsx("svg", { width: "14", height: "8", viewBox: "0 0 14 8", "aria-hidden": true, className: "shrink-0", children: _jsx("line", { x1: "1", y1: "4", x2: "13", y2: "4", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeDasharray: pattern === "dashed" ? "4 3" : pattern === "dotted" ? "0.5 3" : undefined }) }));
167
173
  return _jsx("span", { "aria-hidden": true, className: "size-2 shrink-0 rounded-[3px]", style: { background: color } });
@@ -35,7 +35,7 @@ export function ChartTooltipContent({ active, payload, label, indicator, showTot
35
35
  return (_jsxs("div", { "data-slot": "chart-tooltip", className: cn("vui-chart-tooltip min-w-36 rounded-ui-sm px-2.5 py-2 text-[12px]", className), children: [header ? _jsx("div", { className: "mb-1.5 font-medium text-fg", children: header }) : null, _jsxs("div", { className: "grid gap-1", children: [rows.map((p) => {
36
36
  const key = String(p.dataKey);
37
37
  const s = chart.series.find((x) => x.key === key);
38
- return (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(ChartIndicator, { color: seriesColor(key), variant: ind, pattern: s?.pattern }), _jsx("span", { className: "me-auto text-fg-muted", children: s?.label ?? String(p.name ?? key) }), _jsx("span", { className: "font-mono text-fg tabular", children: chart.formatSeries(key, raw[key] ?? p.value) }), showShare && total ? _jsx("span", { className: "w-11 text-end font-mono text-fg-subtle tabular", children: chart.f.percent(numeric(key) / total) }) : null] }, key));
38
+ return (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(ChartIndicator, { color: seriesColor(key), variant: chart.isBar(key) ? "dot" : ind, pattern: chart.isBar(key) ? undefined : s?.pattern }), _jsx("span", { className: "me-auto text-fg-muted", children: s?.label ?? String(p.name ?? key) }), _jsx("span", { className: "font-mono text-fg tabular", children: chart.formatSeries(key, raw[key] ?? p.value) }), showShare && total ? _jsx("span", { className: "w-11 text-end font-mono text-fg-subtle tabular", children: chart.f.percent(numeric(key) / total) }) : null] }, key));
39
39
  }), showTotal && rows.length > 1 ? (_jsxs("div", { className: "mt-0.5 flex items-center gap-2 border-t border-line pt-1.5", children: [_jsx("span", { className: "me-auto text-fg-muted", children: chart.t("total") }), _jsx("span", { className: "font-mono font-medium text-fg tabular", children: chart.formatSeries(String(rows[0]?.dataKey), total) })] })) : null] })] }));
40
40
  }
41
41
  /** Recharts Tooltip wired to `ChartTooltipContent` and the themed cursor. */
@@ -5,7 +5,7 @@ import { Area, Bar, ComposedChart, Line } from "recharts";
5
5
  import { useLocale } from "../lib/locale.js";
6
6
  import { Chart, useChart } from "./chart-shell.js";
7
7
  import { ChartFrame, ChartGrid, ChartTooltip, ChartXAxis, ChartYAxis, useValueAxisWidth } from "./chart.js";
8
- import { alignZeroDomains, extent, patternDash, seriesColor } from "./utils.js";
8
+ import { alignedAxes, extent, patternDash, seriesColor } from "./utils.js";
9
9
  /**
10
10
  * Volume and rate on two axes — bars on the start axis, a line on the end axis, zero lines aligned
11
11
  * so neither scale exaggerates. Axis sides are logical and swap in RTL.
@@ -15,7 +15,7 @@ import { alignZeroDomains, extent, patternDash, seriesColor } from "./utils.js";
15
15
  * ```
16
16
  */
17
17
  export function ComboChart({ bars, lines, areas = [], endAxisFormat, endAxis = true, stackBars, startAxisLabel, endAxisLabel, ...props }) {
18
- return (_jsx(Chart, { skeleton: "bar", ...props, children: _jsx(ComboPlot, { bars: bars, lines: lines, areas: areas, endAxisFormat: endAxisFormat, endAxis: endAxis, stackBars: stackBars, startAxisLabel: startAxisLabel, endAxisLabel: endAxisLabel }) }));
18
+ return (_jsx(Chart, { skeleton: "bar", barKeys: bars, ...props, children: _jsx(ComboPlot, { bars: bars, lines: lines, areas: areas, endAxisFormat: endAxisFormat, endAxis: endAxis, stackBars: stackBars, startAxisLabel: startAxisLabel, endAxisLabel: endAxisLabel }) }));
19
19
  }
20
20
  function ComboPlot({ bars, lines, areas = [], endAxisFormat, endAxis, stackBars, startAxisLabel, endAxisLabel }) {
21
21
  const chart = useChart();
@@ -27,20 +27,18 @@ function ComboPlot({ bars, lines, areas = [], endAxisFormat, endAxis, stackBars,
27
27
  const startStacked = Boolean(stackBars);
28
28
  const endFormat = endAxisFormat ?? chart.config[endKeys[0] ?? ""]?.format;
29
29
  const startFormat = chart.config[startKeys[0] ?? ""]?.format ?? chart.yFormat;
30
- const [startDomain, endDomain] = React.useMemo(() => {
30
+ const { domains: [startDomain, endDomain], ticks: [startTicks, endTicks] } = React.useMemo(() => {
31
31
  const a = extent(chart.data, startKeys, startStacked);
32
32
  const b = extent(chart.data, endKeys);
33
- return alignZeroDomains(a, b);
33
+ return alignedAxes(a, b);
34
34
  // eslint-disable-next-line react-hooks/exhaustive-deps
35
35
  }, [chart.data, startKeys.join(), endKeys.join(), startStacked]);
36
- // Non-negative data: four equal steps on both axes, so the grid lines serve both scales.
37
- const ticksOf = (d) => (d[0] === 0 ? [0, 1, 2, 3, 4].map((i) => Number(((d[1] * i) / 4).toPrecision(12))) : undefined);
38
36
  const startWidth = useValueAxisWidth(startKeys, { stacked: startStacked, format: startFormat });
39
37
  const endWidth = useValueAxisWidth(endKeys, { format: endFormat });
40
38
  const left = rtl ? "end" : "start";
41
39
  const yId = (key, fallback) => axisOf(key, fallback);
42
40
  const titleProps = (value, side) => value ? { value, angle: -90, position: side === "left" ? "insideLeft" : "insideRight", className: "vui-chart-axis-title", offset: 0, style: { textAnchor: "middle" } } : undefined;
43
- return (_jsx(ChartFrame, { children: _jsxs(ComposedChart, { data: chart.data, stackOffset: startStacked && startDomain[0] < 0 ? "sign" : undefined, margin: { top: 8, right: 4, bottom: 0, left: 4 }, barCategoryGap: "30%", children: [_jsx(ChartGrid, { yAxisId: "start" }), _jsx(ChartXAxis, {}), _jsx(ChartYAxis, { yAxisId: "start", orientation: left === "start" ? "left" : "right", domain: startDomain, ticks: ticksOf(startDomain), width: startWidth + (startAxisLabel ? 16 : 0), tickFormatter: (v) => chart.formatTick(v, startFormat), label: titleProps(startAxisLabel, left === "start" ? "left" : "right"), keys: startKeys }), _jsx(ChartYAxis, { yAxisId: "end", orientation: left === "start" ? "right" : "left", domain: endDomain, ticks: ticksOf(endDomain), hide: !endAxis || endKeys.length === 0, width: endWidth + (endAxisLabel ? 16 : 0), tickFormatter: (v) => chart.formatTick(v, endFormat), label: titleProps(endAxisLabel, left === "start" ? "right" : "left"), keys: endKeys }), _jsx(ChartTooltip, { cursor: { fill: "var(--hover)" } }), areas.map((key) => (_jsx(Area, { yAxisId: yId(key, "start"), dataKey: key, name: chart.config[key]?.label, hide: chart.isHidden(key), type: "monotone", stroke: seriesColor(key), strokeWidth: 1.5, fill: `color-mix(in oklch, ${seriesColor(key)} 16%, transparent)`, isAnimationActive: chart.animate }, key))), bars.map((key, i) => (_jsx(Bar, { yAxisId: yId(key, "start"), dataKey: key, name: chart.config[key]?.label, hide: chart.isHidden(key), stackId: stackBars ? "bars" : undefined, fill: seriesColor(key), radius: stackBars && i < bars.length - 1 ? 0 : [4, 4, 0, 0], maxBarSize: 40, isAnimationActive: chart.animate }, key))), lines.map((key) => {
41
+ return (_jsx(ChartFrame, { children: _jsxs(ComposedChart, { data: chart.data, stackOffset: startStacked && startDomain[0] < 0 ? "sign" : undefined, margin: { top: 8, right: 4, bottom: 0, left: 4 }, barCategoryGap: "30%", children: [_jsx(ChartGrid, { yAxisId: "start" }), _jsx(ChartXAxis, {}), _jsx(ChartYAxis, { yAxisId: "start", orientation: left === "start" ? "left" : "right", domain: startDomain, ticks: startTicks, width: startWidth + (startAxisLabel ? 16 : 0), tickFormatter: (v) => chart.formatTick(v, startFormat), label: titleProps(startAxisLabel, left === "start" ? "left" : "right"), keys: startKeys }), _jsx(ChartYAxis, { yAxisId: "end", orientation: left === "start" ? "right" : "left", domain: endDomain, ticks: endTicks, hide: !endAxis || endKeys.length === 0, width: endWidth + (endAxisLabel ? 16 : 0), tickFormatter: (v) => chart.formatTick(v, endFormat), label: titleProps(endAxisLabel, left === "start" ? "right" : "left"), keys: endKeys }), _jsx(ChartTooltip, { cursor: { fill: "var(--hover)" } }), areas.map((key) => (_jsx(Area, { yAxisId: yId(key, "start"), dataKey: key, name: chart.config[key]?.label, hide: chart.isHidden(key), type: "monotone", stroke: seriesColor(key), strokeWidth: 1.5, fill: `color-mix(in oklch, ${seriesColor(key)} 16%, transparent)`, isAnimationActive: chart.animate }, key))), bars.map((key, i) => (_jsx(Bar, { yAxisId: yId(key, "start"), dataKey: key, name: chart.config[key]?.label, hide: chart.isHidden(key), stackId: stackBars ? "bars" : undefined, fill: seriesColor(key), radius: stackBars && i < bars.length - 1 ? 0 : [4, 4, 0, 0], maxBarSize: 40, isAnimationActive: chart.animate }, key))), lines.map((key) => {
44
42
  const s = chart.series.find((x) => x.key === key);
45
43
  return (_jsx(Line, { yAxisId: yId(key, "end"), dataKey: key, name: s?.label, hide: chart.isHidden(key), type: "monotone", stroke: seriesColor(key), strokeWidth: 2, strokeDasharray: patternDash(s?.pattern), dot: { r: 2.5, fill: seriesColor(key), stroke: "var(--chart-tooltip)", strokeWidth: 1.5 }, activeDot: { r: 4, strokeWidth: 2, stroke: "var(--chart-tooltip)", fill: seriesColor(key) }, isAnimationActive: chart.animate }, key));
46
44
  })] }) }));
@@ -55,7 +55,7 @@ export function DonutChart({ data, nameKey, valueKey, config, center = "total",
55
55
  const ctx = React.useMemo(() => ({ active, setActive, raw: slices }), [active, setActive, slices]);
56
56
  return (_jsx(DonutContext.Provider, { value: ctx, children: _jsx(Chart, { ...props, data: slices, config: effectiveConfig, height: height, legend: "none", skeleton: "donut", summary: summaryText, table: table, state: props.state ?? (rows.length === 0 ? { status: "empty" } : undefined), aside: legend === "none" ? undefined : _jsx(DonutLegend, {}), asidePosition: legend === "bottom" ? "bottom" : "side", children: _jsx(DonutPlot, { px: px, height: height, variant: variant, center: center, centerLabel: centerLabel }) }) }));
57
57
  }
58
- const DonutContext = React.createContext(null);
58
+ const DonutContext = /*#__PURE__*/ React.createContext(null);
59
59
  const useDonut = () => React.useContext(DonutContext);
60
60
  function useSlices(slices) {
61
61
  const chart = useChart();
@@ -26,7 +26,7 @@ export const funnelLabels = {
26
26
  * <Funnel title="Sales pipeline" steps={[{ key: "leads", label: "Leads", value: 1240 }, …]} />
27
27
  * ```
28
28
  */
29
- export const Funnel = React.forwardRef(function Funnel({ steps, orientation = "horizontal", format = "integer", amountFormat = "currency", show = ["conversion", "dropoff"], color = "chart-1", compareTo, onStepClick, size = "md", loading, title, labels, className, style, ...props }, ref) {
29
+ export const Funnel = /*#__PURE__*/ React.forwardRef(function Funnel({ steps, orientation = "horizontal", format = "integer", amountFormat = "currency", show = ["conversion", "dropoff"], color = "chart-1", compareTo, onStepClick, size = "md", loading, title, labels, className, style, ...props }, ref) {
30
30
  const f = useFormat();
31
31
  const t = useLabels("funnel", funnelLabels, labels);
32
32
  const first = steps[0]?.value ?? 0;