@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.
- package/README.md +4 -0
- package/dist/blocks/block-heading.js +1 -1
- package/dist/blocks/block-image.js +1 -1
- package/dist/blocks/block-link.js +2 -2
- package/dist/blocks/index.d.ts +5 -5
- package/dist/blocks/index.js +5 -5
- package/dist/blocks/labels.d.ts +8 -0
- package/dist/blocks/labels.js +60 -0
- package/dist/blocks/section-header.js +1 -1
- package/dist/blocks/section.js +2 -2
- package/dist/blocks/site/_kit-1.js +1 -1
- package/dist/blocks/site/announcement-bar.js +1 -1
- package/dist/blocks/site/article-layout.d.ts +1 -0
- package/dist/blocks/site/article-layout.js +2 -1
- package/dist/blocks/site/blog-list.d.ts +1 -0
- package/dist/blocks/site/blog-list.js +3 -2
- package/dist/blocks/site/contact-dock.js +3 -1
- package/dist/blocks/site/contact-form.js +1 -1
- package/dist/blocks/site/cta.d.ts +2 -2
- package/dist/blocks/site/cta.js +6 -4
- package/dist/blocks/site/feature-grid.d.ts +1 -0
- package/dist/blocks/site/feature-grid.js +5 -4
- package/dist/blocks/site/feature-tabs.js +1 -1
- package/dist/blocks/site/footer.d.ts +11 -2
- package/dist/blocks/site/footer.js +36 -11
- package/dist/blocks/site/gallery-section.d.ts +6 -1
- package/dist/blocks/site/gallery-section.js +5 -4
- package/dist/blocks/site/hero.d.ts +3 -2
- package/dist/blocks/site/hero.js +7 -5
- package/dist/blocks/site/logo-strip.d.ts +1 -0
- package/dist/blocks/site/logo-strip.js +1 -1
- package/dist/blocks/site/map-hours.d.ts +2 -2
- package/dist/blocks/site/map-hours.js +4 -2
- package/dist/blocks/site/media-text.d.ts +4 -1
- package/dist/blocks/site/media-text.js +4 -3
- package/dist/blocks/site/menu-list.d.ts +7 -3
- package/dist/blocks/site/menu-list.js +34 -7
- package/dist/blocks/site/navbar.d.ts +1 -0
- package/dist/blocks/site/navbar.js +6 -5
- package/dist/blocks/site/not-found.js +2 -1
- package/dist/blocks/site/page-intro.d.ts +1 -0
- package/dist/blocks/site/page-intro.js +2 -1
- package/dist/blocks/site/process.d.ts +1 -0
- package/dist/blocks/site/process.js +2 -1
- package/dist/blocks/site/registry-1.d.ts +1 -1
- package/dist/blocks/site/registry-2.d.ts +5 -0
- package/dist/blocks/site/registry-2.js +5 -3
- package/dist/blocks/site/rich-text-section.js +2 -1
- package/dist/blocks/site/shared/heading-lines.d.ts +9 -0
- package/dist/blocks/site/shared/heading-lines.js +32 -0
- package/dist/blocks/site/shared/image-sizes.d.ts +25 -0
- package/dist/blocks/site/shared/image-sizes.js +37 -0
- package/dist/blocks/site/shared/island-keys.d.ts +1 -1
- package/dist/blocks/site/shared/island-keys.js +1 -1
- package/dist/blocks/site/shared/labels-2.d.ts +17 -1
- package/dist/blocks/site/shared/labels-2.js +832 -6
- package/dist/blocks/site/shared/open-now.d.ts +1 -1
- package/dist/blocks/site/shared/open-now.js +1 -1
- package/dist/blocks/site/shared/opening-hours.d.ts +18 -2
- package/dist/blocks/site/shared/opening-hours.js +36 -7
- package/dist/blocks/site/shared/tap.d.ts +9 -0
- package/dist/blocks/site/shared/tap.js +16 -0
- package/dist/blocks/site/site-shell.js +3 -3
- package/dist/blocks/site/team.d.ts +1 -1
- package/dist/blocks/site/team.js +4 -3
- package/dist/blocks/site/testimonials.d.ts +2 -2
- package/dist/blocks/site/testimonials.js +3 -3
- package/dist/business/approval-flow.js +2 -2
- package/dist/business/import-wizard.js +1 -1
- package/dist/business/line-items.js +1 -1
- package/dist/business/multi-step-form.js +2 -2
- package/dist/business/permission-matrix.js +1 -1
- package/dist/business/setup-checklist.js +2 -2
- package/dist/business/signer-status.js +1 -1
- package/dist/charts/bar-chart.js +1 -1
- package/dist/charts/bar-list.js +1 -1
- package/dist/charts/chart-shell.d.ts +9 -2
- package/dist/charts/chart-shell.js +11 -5
- package/dist/charts/chart.js +1 -1
- package/dist/charts/combo-chart.js +5 -7
- package/dist/charts/donut-chart.js +1 -1
- package/dist/charts/funnel.js +1 -1
- package/dist/charts/gauge.js +2 -2
- package/dist/charts/utils.d.ts +10 -0
- package/dist/charts/utils.js +46 -0
- package/dist/components/accordion.d.ts +1 -1
- package/dist/components/accordion.js +8 -8
- package/dist/components/activity-timeline.js +11 -11
- package/dist/components/address-field.js +3 -3
- package/dist/components/alert-dialog.d.ts +1 -1
- package/dist/components/alert-dialog.js +8 -8
- package/dist/components/alert.js +2 -2
- package/dist/components/app-shell.js +3 -3
- package/dist/components/aspect-ratio.d.ts +26 -0
- package/dist/components/aspect-ratio.js +42 -0
- package/dist/components/attachment-list.js +2 -2
- package/dist/components/audit-log.js +1 -1
- package/dist/components/avatar.d.ts +1 -1
- package/dist/components/avatar.js +8 -8
- package/dist/components/backup-codes.js +1 -1
- package/dist/components/badge.js +3 -3
- package/dist/components/breadcrumb.js +10 -9
- package/dist/components/button-group.js +4 -4
- package/dist/components/button.js +4 -4
- package/dist/components/calendar.js +5 -5
- package/dist/components/card.js +8 -8
- package/dist/components/carousel.d.ts +12 -3
- package/dist/components/carousel.js +17 -14
- package/dist/components/checkbox.d.ts +1 -1
- package/dist/components/checkbox.js +6 -6
- package/dist/components/collapsible.d.ts +36 -0
- package/dist/components/collapsible.js +37 -0
- package/dist/components/color-picker.js +3 -3
- package/dist/components/combobox.js +1 -1
- package/dist/components/command.js +9 -9
- package/dist/components/comment-thread.js +3 -3
- package/dist/components/context-menu.d.ts +1 -1
- package/dist/components/context-menu.js +9 -9
- package/dist/components/currency-input.js +1 -1
- package/dist/components/date-picker.js +2 -2
- package/dist/components/date-range-picker.js +1 -1
- package/dist/components/description-list.js +2 -2
- package/dist/components/dialog.d.ts +1 -1
- package/dist/components/dialog.js +9 -9
- package/dist/components/dropdown-menu.d.ts +1 -1
- package/dist/components/dropdown-menu.js +9 -9
- package/dist/components/editor-layout.js +9 -9
- package/dist/components/empty-state.js +2 -2
- package/dist/components/entity-card.js +1 -1
- package/dist/components/file-upload.js +5 -5
- package/dist/components/formatted-input.js +3 -3
- package/dist/components/hierarchy-chart.js +1 -1
- package/dist/components/hover-card.d.ts +1 -1
- package/dist/components/hover-card.js +3 -3
- package/dist/components/iban-input.js +1 -1
- package/dist/components/id-input.js +3 -3
- package/dist/components/image.d.ts +18 -2
- package/dist/components/image.js +16 -9
- package/dist/components/input-otp.js +6 -6
- package/dist/components/input.d.ts +1 -1
- package/dist/components/input.js +6 -6
- package/dist/components/item.js +4 -4
- package/dist/components/kbd.js +3 -3
- package/dist/components/list-layout.js +9 -9
- package/dist/components/menubar.d.ts +96 -0
- package/dist/components/menubar.js +123 -0
- package/dist/components/native-select.js +1 -1
- package/dist/components/navigation-menu.d.ts +1 -1
- package/dist/components/navigation-menu.js +12 -11
- package/dist/components/notification-center.js +4 -4
- package/dist/components/page-header.js +3 -3
- package/dist/components/pagination.js +9 -9
- package/dist/components/phone-input.js +1 -1
- package/dist/components/pin-map.js +1 -1
- package/dist/components/placeholder-art.d.ts +51 -0
- package/dist/components/placeholder-art.js +82 -0
- package/dist/components/popover.d.ts +1 -1
- package/dist/components/popover.js +7 -7
- package/dist/components/progress.js +3 -3
- package/dist/components/qr-code.js +1 -1
- package/dist/components/radio-group.d.ts +1 -1
- package/dist/components/radio-group.js +4 -4
- package/dist/components/record-detail-layout.js +10 -10
- package/dist/components/record-picker.js +2 -2
- package/dist/components/resizable.js +2 -2
- package/dist/components/scroll-area.d.ts +1 -1
- package/dist/components/scroll-area.js +4 -4
- package/dist/components/select.d.ts +1 -1
- package/dist/components/select.js +10 -10
- package/dist/components/separator.d.ts +1 -1
- package/dist/components/separator.js +3 -3
- package/dist/components/settings-layout.js +6 -6
- package/dist/components/sheet.js +3 -3
- package/dist/components/sidebar.js +12 -11
- package/dist/components/signature-pad.js +1 -1
- package/dist/components/skeleton.js +5 -5
- package/dist/components/sla-timer.js +2 -2
- package/dist/components/slider.d.ts +1 -1
- package/dist/components/slider.js +2 -2
- package/dist/components/slug-input.js +1 -1
- package/dist/components/sparkline.js +1 -1
- package/dist/components/spinner.js +2 -2
- package/dist/components/stat.js +5 -5
- package/dist/components/status-picker.js +2 -2
- package/dist/components/stepper.js +1 -1
- package/dist/components/switch.d.ts +1 -1
- package/dist/components/switch.js +3 -3
- package/dist/components/table.js +10 -10
- package/dist/components/tabs.d.ts +1 -1
- package/dist/components/tabs.js +11 -11
- package/dist/components/tag-input.js +1 -1
- package/dist/components/task-list.js +1 -1
- package/dist/components/time-picker.js +3 -3
- package/dist/components/toggle.d.ts +2 -1
- package/dist/components/toggle.js +7 -6
- package/dist/components/tooltip.d.ts +1 -1
- package/dist/components/tooltip.js +5 -4
- package/dist/components/top-bar.js +4 -4
- package/dist/components/tour.js +1 -1
- package/dist/components/tree-select.js +2 -2
- package/dist/components/tree-view.js +3 -3
- package/dist/components/typography.js +11 -11
- package/dist/components/user-picker.js +2 -2
- package/dist/components/version-history.js +3 -3
- package/dist/data-table/data-table.js +1 -1
- package/dist/data-table/filter-bar.js +2 -2
- package/dist/data-table/index.d.ts +15 -8
- package/dist/data-table/index.js +9 -8
- package/dist/data-table/saved-views.js +1 -1
- package/dist/editor/block-editor.js +1 -1
- package/dist/editor/context.js +1 -1
- package/dist/editor/menus.js +1 -1
- package/dist/fonts/font-picker.js +3 -3
- package/dist/fonts/pairing-picker.js +1 -1
- package/dist/fonts/provider.js +1 -1
- package/dist/index.d.ts +188 -90
- package/dist/index.js +94 -90
- package/dist/lib/data-islands.js +1 -1
- package/dist/lib/field-context.js +1 -1
- package/dist/lib/floating-arrow.js +1 -1
- package/dist/lib/islands.js +1 -1
- package/dist/lib/layer.js +3 -3
- package/dist/lib/locale.js +2 -2
- package/dist/lib/menu.js +2 -2
- package/dist/lib/provider.js +4 -4
- package/dist/lib/theme-scope.js +4 -3
- package/dist/lib/value-format.js +1 -1
- package/dist/lib/variants.js +2 -2
- package/dist/locales/ar.d.ts +2087 -0
- package/dist/locales/ar.js +2088 -0
- package/dist/locales/de.d.ts +2087 -0
- package/dist/locales/de.js +2088 -0
- package/dist/locales/en.d.ts +1 -0
- package/dist/locales/en.js +1 -0
- package/dist/locales/es.d.ts +2087 -0
- package/dist/locales/es.js +2087 -0
- package/dist/locales/fr.d.ts +2087 -0
- package/dist/locales/fr.js +2088 -0
- package/dist/locales/tr.d.ts +1 -0
- package/dist/locales/tr.js +1 -0
- package/dist/media/focal-point.js +1 -1
- package/dist/media/gallery.js +1 -1
- package/dist/media/image-cropper.js +1 -1
- package/dist/media/image-field.js +2 -2
- package/dist/media/lightbox.js +4 -3
- package/dist/media/link-preview.js +3 -3
- package/dist/media/media-library.js +4 -4
- package/dist/media/media-picker.js +1 -1
- package/dist/media/media-provider.js +1 -1
- package/dist/media/video-player.js +4 -4
- package/dist/motion/count-up.js +1 -1
- package/dist/motion/motion-scope.js +2 -2
- package/dist/motion/page-transition.js +1 -1
- package/dist/motion/parallax.js +2 -2
- package/dist/motion/pointer.js +3 -3
- package/dist/motion/reveal.js +3 -3
- package/dist/motion/skeleton-swap.js +1 -1
- package/dist/motion/text-reveal.d.ts +3 -1
- package/dist/motion/text-reveal.js +6 -4
- package/dist/motion/ticker.js +1 -1
- package/dist/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/dist/render/block-renderer.js +1 -1
- package/dist/scheduler/gantt.js +2 -2
- package/dist/scheduler/resource-calendar.js +2 -2
- package/dist/scheduler/scheduler.js +3 -3
- package/dist/scheduler/time-tracker.js +4 -4
- package/dist/sortable/kanban.js +2 -2
- package/dist/sortable/sortable-list.js +2 -2
- package/dist/sortable/sortable.js +4 -4
- package/dist/styles/blocks.css +18 -9
- package/dist/styles/editors.css +2 -1
- package/dist/styles/media.css +31 -5
- package/dist/styles.css +39 -9
- package/package.json +1 -1
|
@@ -15,7 +15,7 @@ export interface OpenNowProps {
|
|
|
15
15
|
className?: string;
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
|
-
* "Open
|
|
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
|
|
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
|
-
/**
|
|
114
|
-
export
|
|
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
|
-
|
|
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.
|
|
236
|
-
const
|
|
237
|
-
return
|
|
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
|
|
243
|
-
const
|
|
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"). */
|
package/dist/blocks/site/team.js
CHANGED
|
@@ -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:
|
|
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:
|
|
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
|
|
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();
|
package/dist/charts/bar-chart.js
CHANGED
|
@@ -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();
|
package/dist/charts/bar-list.js
CHANGED
|
@@ -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
|
-
|
|
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 } });
|
package/dist/charts/chart.js
CHANGED
|
@@ -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 {
|
|
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
|
|
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:
|
|
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();
|
package/dist/charts/funnel.js
CHANGED
|
@@ -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;
|