@raydenui/ui 0.9.7 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Table-DCNSxua1.d.cts +31 -0
- package/dist/Table-DCNSxua1.d.ts +31 -0
- package/dist/blocks/ApplicationShellBlock.cjs +157 -0
- package/dist/blocks/ApplicationShellBlock.js +154 -0
- package/dist/blocks/CheckoutReviewBlock.cjs +16 -0
- package/dist/blocks/CheckoutReviewBlock.js +13 -0
- package/dist/blocks/CommandPaletteBlock.cjs +334 -0
- package/dist/blocks/CommandPaletteBlock.js +331 -0
- package/dist/blocks/CreateAccountBlock.cjs +147 -0
- package/dist/blocks/CreateAccountBlock.js +143 -0
- package/dist/blocks/EmptyStateBlock.cjs +19 -0
- package/dist/blocks/EmptyStateBlock.js +16 -0
- package/dist/blocks/FeatureOverviewBlock.cjs +54 -0
- package/dist/blocks/FeatureOverviewBlock.js +51 -0
- package/dist/blocks/HeaderBlock.cjs +230 -0
- package/dist/blocks/HeaderBlock.js +227 -0
- package/dist/blocks/KpiOverviewBlock.cjs +63 -0
- package/dist/blocks/KpiOverviewBlock.js +60 -0
- package/dist/blocks/LoginBlock.cjs +66 -0
- package/dist/blocks/LoginBlock.js +63 -0
- package/dist/blocks/NotificationsBlock.cjs +17 -0
- package/dist/blocks/NotificationsBlock.js +14 -0
- package/dist/blocks/PageHeaderBlock.cjs +121 -0
- package/dist/blocks/PageHeaderBlock.js +118 -0
- package/dist/blocks/PricingPlansBlock.cjs +146 -0
- package/dist/blocks/PricingPlansBlock.js +143 -0
- package/dist/blocks/ProductCollectionBlock.cjs +37 -0
- package/dist/blocks/ProductCollectionBlock.js +34 -0
- package/dist/blocks/ProductDetailBlock.cjs +30 -0
- package/dist/blocks/ProductDetailBlock.js +27 -0
- package/dist/blocks/ProductHeroBlock.cjs +83 -0
- package/dist/blocks/ProductHeroBlock.js +80 -0
- package/dist/blocks/ProfileSettingsBlock.cjs +130 -0
- package/dist/blocks/ProfileSettingsBlock.js +126 -0
- package/dist/blocks/QuickSendBlock.cjs +11 -0
- package/dist/blocks/QuickSendBlock.js +8 -0
- package/dist/blocks/RecentTransactionsBlock.cjs +13 -0
- package/dist/blocks/RecentTransactionsBlock.js +10 -0
- package/dist/blocks/SearchableTableBlock.cjs +91 -0
- package/dist/blocks/SearchableTableBlock.js +88 -0
- package/dist/blocks/ShoppingCartBlock.cjs +16 -0
- package/dist/blocks/ShoppingCartBlock.js +13 -0
- package/dist/blocks/SiteFooterBlock.cjs +69 -0
- package/dist/blocks/SiteFooterBlock.js +66 -0
- package/dist/blocks/TableBlock.cjs +20 -0
- package/dist/blocks/TableBlock.js +17 -0
- package/dist/blocks/TaskListBlock.cjs +198 -0
- package/dist/blocks/TaskListBlock.js +195 -0
- package/dist/blocks/WorkspaceSwitcherBlock.cjs +291 -0
- package/dist/blocks/WorkspaceSwitcherBlock.js +288 -0
- package/dist/blocks/commerce.cjs +44 -0
- package/dist/blocks/commerce.js +35 -0
- package/dist/blocks/index.cjs +53 -0
- package/dist/blocks/index.js +24 -0
- package/dist/blocks.d.cts +1820 -0
- package/dist/blocks.d.ts +1820 -0
- package/dist/chart.cjs +13 -0
- package/dist/chart.d.cts +59 -0
- package/dist/chart.d.ts +59 -0
- package/dist/chart.js +5 -0
- package/dist/components/Accordion/Accordion.cjs +94 -0
- package/dist/components/Accordion/Accordion.js +91 -0
- package/dist/components/Accordion/index.cjs +8 -0
- package/dist/components/Accordion/index.js +1 -0
- package/dist/components/ActivityFeed/ActivityContent.cjs +40 -0
- package/dist/components/ActivityFeed/ActivityContent.js +37 -0
- package/dist/components/ActivityFeed/ActivityItem.cjs +19 -0
- package/dist/components/ActivityFeed/ActivityItem.js +16 -0
- package/dist/components/ActivityFeed/index.cjs +7 -0
- package/dist/components/ActivityFeed/index.js +2 -0
- package/dist/components/Alert/Alert.cjs +42 -0
- package/dist/components/Alert/Alert.js +39 -0
- package/dist/components/Alert/index.cjs +5 -0
- package/dist/components/Alert/index.js +1 -0
- package/dist/components/Avatar/Avatar.cjs +101 -0
- package/dist/components/Avatar/Avatar.js +98 -0
- package/dist/components/Avatar/index.cjs +6 -0
- package/dist/components/Avatar/index.js +1 -0
- package/dist/components/Badge/Badge.cjs +53 -0
- package/dist/components/Badge/Badge.js +50 -0
- package/dist/components/Badge/index.cjs +5 -0
- package/dist/components/Badge/index.js +1 -0
- package/dist/components/Banner/Banner.cjs +83 -0
- package/dist/components/Banner/Banner.js +80 -0
- package/dist/components/Banner/index.cjs +5 -0
- package/dist/components/Banner/index.js +1 -0
- package/dist/components/Breadcrumb/Breadcrumb.cjs +31 -0
- package/dist/components/Breadcrumb/Breadcrumb.js +28 -0
- package/dist/components/Breadcrumb/index.cjs +5 -0
- package/dist/components/Breadcrumb/index.js +1 -0
- package/dist/components/Button/Button.cjs +88 -0
- package/dist/components/Button/Button.js +85 -0
- package/dist/components/Button/index.cjs +5 -0
- package/dist/components/Button/index.js +1 -0
- package/dist/components/ButtonGroup/ButtonGroup.cjs +8 -0
- package/dist/components/ButtonGroup/ButtonGroup.js +5 -0
- package/dist/components/ButtonGroup/ButtonGroupItem.cjs +15 -0
- package/dist/components/ButtonGroup/ButtonGroupItem.js +12 -0
- package/dist/components/ButtonGroup/index.cjs +7 -0
- package/dist/components/ButtonGroup/index.js +2 -0
- package/dist/components/Card/Card.cjs +94 -0
- package/dist/components/Card/Card.js +91 -0
- package/dist/components/Card/index.cjs +9 -0
- package/dist/components/Card/index.js +1 -0
- package/dist/components/Chart/Chart.cjs +160 -0
- package/dist/components/Chart/Chart.js +153 -0
- package/dist/components/Chart/index.cjs +10 -0
- package/dist/components/Chart/index.js +2 -0
- package/dist/components/Chart/theme.cjs +67 -0
- package/dist/components/Chart/theme.js +62 -0
- package/dist/components/Chip/Chip.cjs +18 -0
- package/dist/components/Chip/Chip.js +15 -0
- package/dist/components/Chip/index.cjs +5 -0
- package/dist/components/Chip/index.js +1 -0
- package/dist/components/Counter/Counter.cjs +74 -0
- package/dist/components/Counter/Counter.js +71 -0
- package/dist/components/Counter/index.cjs +6 -0
- package/dist/components/Counter/index.js +1 -0
- package/dist/components/DatePicker/DatePicker.cjs +343 -0
- package/dist/components/DatePicker/DatePicker.js +340 -0
- package/dist/components/DatePicker/index.cjs +5 -0
- package/dist/components/DatePicker/index.js +1 -0
- package/dist/components/Divider/Divider.cjs +31 -0
- package/dist/components/Divider/Divider.js +28 -0
- package/dist/components/Divider/index.cjs +5 -0
- package/dist/components/Divider/index.js +1 -0
- package/dist/components/DropdownMenu/DropdownMenu.cjs +108 -0
- package/dist/components/DropdownMenu/DropdownMenu.js +105 -0
- package/dist/components/DropdownMenu/index.cjs +11 -0
- package/dist/components/DropdownMenu/index.js +1 -0
- package/dist/components/EmptyStateIllustration/EmptyStateIllustration.cjs +42 -0
- package/dist/components/EmptyStateIllustration/EmptyStateIllustration.js +39 -0
- package/dist/components/EmptyStateIllustration/illustrations.cjs +3322 -0
- package/dist/components/EmptyStateIllustration/illustrations.js +3319 -0
- package/dist/components/EmptyStateIllustration/index.cjs +7 -0
- package/dist/components/EmptyStateIllustration/index.js +2 -0
- package/dist/components/FileUpload/FileUpload.cjs +116 -0
- package/dist/components/FileUpload/FileUpload.js +113 -0
- package/dist/components/FileUpload/FileUploadDropZone.cjs +58 -0
- package/dist/components/FileUpload/FileUploadDropZone.js +55 -0
- package/dist/components/FileUpload/FileUploadIcons.cjs +55 -0
- package/dist/components/FileUpload/FileUploadIcons.js +50 -0
- package/dist/components/FileUpload/FileUploadItem.cjs +34 -0
- package/dist/components/FileUpload/FileUploadItem.js +31 -0
- package/dist/components/FileUpload/index.cjs +9 -0
- package/dist/components/FileUpload/index.js +3 -0
- package/dist/components/FormControl/Checkbox.cjs +27 -0
- package/dist/components/FormControl/Checkbox.js +24 -0
- package/dist/components/FormControl/Radio.cjs +15 -0
- package/dist/components/FormControl/Radio.js +12 -0
- package/dist/components/FormControl/Toggle.cjs +15 -0
- package/dist/components/FormControl/Toggle.js +12 -0
- package/dist/components/FormControl/index.cjs +9 -0
- package/dist/components/FormControl/index.js +3 -0
- package/dist/components/Icon/Icon.cjs +70 -0
- package/dist/components/Icon/Icon.js +34 -0
- package/dist/components/Icon/catalog.cjs +1672 -0
- package/dist/components/Icon/catalog.js +1669 -0
- package/dist/components/Icon/icons.cjs +5621 -0
- package/dist/components/Icon/icons.js +5610 -0
- package/dist/components/Icon/index.cjs +8 -0
- package/dist/components/Icon/index.js +2 -0
- package/dist/components/Input/Input.cjs +64 -0
- package/dist/components/Input/Input.js +61 -0
- package/dist/components/Input/index.cjs +5 -0
- package/dist/components/Input/index.js +1 -0
- package/dist/components/MetricsCard/MetricsCard.cjs +107 -0
- package/dist/components/MetricsCard/MetricsCard.js +104 -0
- package/dist/components/MetricsCard/index.cjs +5 -0
- package/dist/components/MetricsCard/index.js +1 -0
- package/dist/components/Modal/Modal.cjs +126 -0
- package/dist/components/Modal/Modal.js +123 -0
- package/dist/components/Modal/index.cjs +5 -0
- package/dist/components/Modal/index.js +1 -0
- package/dist/components/Pagination/Pagination.cjs +42 -0
- package/dist/components/Pagination/Pagination.js +39 -0
- package/dist/components/Pagination/index.cjs +5 -0
- package/dist/components/Pagination/index.js +1 -0
- package/dist/components/ProgressBar/ProgressBar.cjs +34 -0
- package/dist/components/ProgressBar/ProgressBar.js +31 -0
- package/dist/components/ProgressBar/index.cjs +5 -0
- package/dist/components/ProgressBar/index.js +1 -0
- package/dist/components/ProgressCircle/ProgressCircle.cjs +34 -0
- package/dist/components/ProgressCircle/ProgressCircle.js +31 -0
- package/dist/components/ProgressCircle/index.cjs +5 -0
- package/dist/components/ProgressCircle/index.js +1 -0
- package/dist/components/Select/Select.cjs +84 -0
- package/dist/components/Select/Select.js +80 -0
- package/dist/components/Select/SelectOption.cjs +26 -0
- package/dist/components/Select/SelectOption.js +23 -0
- package/dist/components/Select/index.cjs +7 -0
- package/dist/components/Select/index.js +2 -0
- package/dist/components/SidebarMenu/SidebarMenu.cjs +85 -0
- package/dist/components/SidebarMenu/SidebarMenu.js +81 -0
- package/dist/components/SidebarMenu/SidebarMenuItem.cjs +126 -0
- package/dist/components/SidebarMenu/SidebarMenuItem.js +122 -0
- package/dist/components/SidebarMenu/SidebarMenuSection.cjs +14 -0
- package/dist/components/SidebarMenu/SidebarMenuSection.js +11 -0
- package/dist/components/SidebarMenu/index.cjs +12 -0
- package/dist/components/SidebarMenu/index.js +4 -0
- package/dist/components/Slider/Slider.cjs +161 -0
- package/dist/components/Slider/Slider.js +158 -0
- package/dist/components/Slider/index.cjs +6 -0
- package/dist/components/Slider/index.js +1 -0
- package/dist/components/Spinner/Spinner.cjs +93 -0
- package/dist/components/Spinner/Spinner.js +90 -0
- package/dist/components/Spinner/index.cjs +5 -0
- package/dist/components/Spinner/index.js +1 -0
- package/dist/components/Stepper/Stepper.cjs +82 -0
- package/dist/components/Stepper/Stepper.js +79 -0
- package/dist/components/Stepper/index.cjs +7 -0
- package/dist/components/Stepper/index.js +1 -0
- package/dist/components/Table/Table.cjs +25 -0
- package/dist/components/Table/Table.js +22 -0
- package/dist/components/Table/index.cjs +10 -0
- package/dist/components/Table/index.js +1 -0
- package/dist/components/Table/useTableSelection.cjs +60 -0
- package/dist/components/Table/useTableSelection.js +57 -0
- package/dist/components/Tabs/Tab.cjs +70 -0
- package/dist/components/Tabs/Tab.js +67 -0
- package/dist/components/Tabs/Tabs.cjs +133 -0
- package/dist/components/Tabs/Tabs.js +129 -0
- package/dist/components/Tabs/index.cjs +7 -0
- package/dist/components/Tabs/index.js +2 -0
- package/dist/components/Tooltip/Tooltip.cjs +101 -0
- package/dist/components/Tooltip/Tooltip.js +98 -0
- package/dist/components/Tooltip/index.cjs +5 -0
- package/dist/components/Tooltip/index.js +1 -0
- package/dist/context/ThemeContext.cjs +97 -0
- package/dist/context/ThemeContext.js +92 -0
- package/dist/fonts/README.md +13 -0
- package/dist/fonts/hanken-grotesk-cyrillic-ext-italic.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-cyrillic-ext-normal.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-latin-ext-italic.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-latin-ext-normal.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-latin-italic.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-latin-normal.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-vietnamese-italic.woff2 +0 -0
- package/dist/fonts/hanken-grotesk-vietnamese-normal.woff2 +0 -0
- package/dist/fonts/hankengrotesk-LICENSE.txt +94 -0
- package/dist/fonts/manrope-LICENSE.txt +93 -0
- package/dist/fonts/manrope-cyrillic-ext-normal.woff2 +0 -0
- package/dist/fonts/manrope-cyrillic-normal.woff2 +0 -0
- package/dist/fonts/manrope-greek-normal.woff2 +0 -0
- package/dist/fonts/manrope-latin-ext-normal.woff2 +0 -0
- package/dist/fonts/manrope-latin-normal.woff2 +0 -0
- package/dist/fonts/manrope-vietnamese-normal.woff2 +0 -0
- package/dist/fonts.css +148 -0
- package/dist/hooks/form/index.cjs +11 -0
- package/dist/hooks/form/index.js +3 -0
- package/dist/hooks/form/useRaydenFormControl.cjs +81 -0
- package/dist/hooks/form/useRaydenFormControl.js +76 -0
- package/dist/hooks/form/useRaydenInput.cjs +38 -0
- package/dist/hooks/form/useRaydenInput.js +35 -0
- package/dist/hooks/form/useRaydenSelect.cjs +45 -0
- package/dist/hooks/form/useRaydenSelect.js +42 -0
- package/dist/hooks/index.cjs +17 -0
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useBodyScrollLock.cjs +24 -0
- package/dist/hooks/useBodyScrollLock.js +21 -0
- package/dist/hooks/useCollisionAwareSide.cjs +72 -0
- package/dist/hooks/useCollisionAwareSide.js +69 -0
- package/dist/hooks/useControllableValue.cjs +16 -0
- package/dist/hooks/useControllableValue.js +13 -0
- package/dist/hooks/useDismissableLayer.cjs +100 -0
- package/dist/hooks/useDismissableLayer.js +97 -0
- package/dist/hooks/usePopupList.cjs +101 -0
- package/dist/hooks/usePopupList.js +98 -0
- package/dist/icons-8yD7I5jO.d.cts +430 -0
- package/dist/icons-8yD7I5jO.d.ts +430 -0
- package/dist/icons.cjs +2111 -418
- package/dist/icons.d.cts +1256 -429
- package/dist/icons.d.ts +1256 -429
- package/dist/icons.js +2089 -1
- package/dist/index.cjs +128 -15046
- package/dist/index.d.cts +697 -662
- package/dist/index.d.ts +697 -662
- package/dist/index.js +43 -14962
- package/dist/motion/Collapse.cjs +28 -0
- package/dist/motion/Collapse.js +25 -0
- package/dist/motion/MotionProvider.cjs +43 -0
- package/dist/motion/MotionProvider.js +38 -0
- package/dist/motion/Pressable.cjs +46 -0
- package/dist/motion/Pressable.js +43 -0
- package/dist/motion/Reveal.cjs +19 -0
- package/dist/motion/Reveal.js +16 -0
- package/dist/motion/SharedLayout.cjs +46 -0
- package/dist/motion/SharedLayout.js +43 -0
- package/dist/motion/index.cjs +19 -0
- package/dist/motion/index.js +6 -0
- package/dist/motion/presence.cjs +58 -0
- package/dist/motion/presence.js +55 -0
- package/dist/motion/presets.cjs +88 -0
- package/dist/motion/presets.js +84 -0
- package/dist/motion.d.cts +51 -0
- package/dist/motion.d.ts +51 -0
- package/dist/preset.cjs +356 -195
- package/dist/preset.d.cts +111 -32
- package/dist/preset.d.ts +111 -32
- package/dist/preset.js +353 -187
- package/dist/presets-Ba5QndHg.d.cts +144 -0
- package/dist/presets-Ba5QndHg.d.ts +144 -0
- package/dist/styles.css +1 -1
- package/dist/utils/cn.cjs +38 -0
- package/dist/utils/cn.js +35 -0
- package/dist/utils/resolveIcon.cjs +18 -0
- package/dist/utils/resolveIcon.js +15 -0
- package/package.json +79 -21
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useId, useRef, useState, } from "react";
|
|
3
|
+
import { cn } from "../utils/cn.js";
|
|
4
|
+
import { Icon } from "../components/Icon/index.js";
|
|
5
|
+
import { Input } from "../components/Input/index.js";
|
|
6
|
+
const TIER = {
|
|
7
|
+
sm: {
|
|
8
|
+
row: "hidden @min-[720px]:flex",
|
|
9
|
+
block: "hidden @min-[720px]:block",
|
|
10
|
+
collapsed: "@min-[720px]:hidden",
|
|
11
|
+
},
|
|
12
|
+
md: {
|
|
13
|
+
row: "hidden @min-[880px]:flex",
|
|
14
|
+
block: "hidden @min-[880px]:block",
|
|
15
|
+
collapsed: "@min-[880px]:hidden",
|
|
16
|
+
},
|
|
17
|
+
lg: {
|
|
18
|
+
row: "hidden @min-[960px]:flex",
|
|
19
|
+
block: "hidden @min-[960px]:block",
|
|
20
|
+
collapsed: "@min-[960px]:hidden",
|
|
21
|
+
},
|
|
22
|
+
xl: {
|
|
23
|
+
row: "hidden @min-[1060px]:flex",
|
|
24
|
+
block: "hidden @min-[1060px]:block",
|
|
25
|
+
collapsed: "@min-[1060px]:hidden",
|
|
26
|
+
},
|
|
27
|
+
xxl: {
|
|
28
|
+
row: "hidden @min-[1280px]:flex",
|
|
29
|
+
block: "hidden @min-[1280px]:block",
|
|
30
|
+
collapsed: "@min-[1280px]:hidden",
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
const VARIANT_TIER = {
|
|
34
|
+
1: "sm",
|
|
35
|
+
2: "lg",
|
|
36
|
+
3: "md",
|
|
37
|
+
4: "md",
|
|
38
|
+
5: "md",
|
|
39
|
+
6: "sm",
|
|
40
|
+
7: "xl",
|
|
41
|
+
8: "xxl",
|
|
42
|
+
9: "sm",
|
|
43
|
+
10: "md",
|
|
44
|
+
11: "sm",
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Shared gutters and a bounded row keep the brand and controls aligned on every variant.
|
|
48
|
+
* Only the surface and announcement stretch on wider screens.
|
|
49
|
+
*/
|
|
50
|
+
const ROW_PADDING = "mx-auto w-full max-w-[1440px] px-4 py-3 @min-[640px]:px-6 @min-[1140px]:px-10 @min-[1140px]:py-4";
|
|
51
|
+
/** Nav rows tighten up between the collapse threshold and a comfortable desktop. */
|
|
52
|
+
const NAV_GAP = "gap-4 @min-[1140px]:gap-6";
|
|
53
|
+
const PILL_GAP = "gap-5 @min-[1140px]:gap-8";
|
|
54
|
+
/**
|
|
55
|
+
* A variant that asks for a dark bar has to stay dark in a globally dark document.
|
|
56
|
+
* The grey ramp inverts under `.dark`, so `bg-grey-900` quietly became a near-white
|
|
57
|
+
* bar with unreadable navigation on top of it.
|
|
58
|
+
*
|
|
59
|
+
* `.rayden-dark` is the shared home for that: it is declared next to `.dark` in
|
|
60
|
+
* globals.css, pins the same surface / foreground / ramp values, and is matched by
|
|
61
|
+
* the `dark:` variant, so the same semantic pairs — `bg-surface`/`text-on-surface`
|
|
62
|
+
* for the bar, `text-on-surface-muted` for muted text — resolve to dark values in
|
|
63
|
+
* *both* global modes, and nested components inherit the same roles. It replaces a
|
|
64
|
+
* block-local inline style object, which no nested component could see through.
|
|
65
|
+
*/
|
|
66
|
+
const DARK_ISLAND = "rayden-dark";
|
|
67
|
+
const FOCUS_RING = "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-action-primary-text";
|
|
68
|
+
// ─── Sub-components ──────────────────────────────────────────────────
|
|
69
|
+
function NavLink({ link, tone = "default", large, className, onNavigate, }) {
|
|
70
|
+
// A link with an href must be an anchor, or it is not a link: no middle-click, no
|
|
71
|
+
// open-in-new-tab, and the wrong role. This holds at every viewport — the collapsed
|
|
72
|
+
// menu used to rebuild links as buttons and drop the href on the floor.
|
|
73
|
+
const Tag = link.href ? "a" : "button";
|
|
74
|
+
return (_jsxs(Tag, { ...(link.href ? { href: link.href } : { type: "button" }), "aria-current": link.active ? "page" : undefined, onClick: () => {
|
|
75
|
+
link.onClick?.();
|
|
76
|
+
onNavigate?.();
|
|
77
|
+
}, className: cn("relative flex min-h-11 items-center gap-2 rounded-md font-medium whitespace-nowrap transition-colors duration-150 motion-reduce:transition-none cursor-pointer", FOCUS_RING, large ? "text-base" : "text-sm", link.active
|
|
78
|
+
? "text-action-primary-text after:absolute after:inset-x-0 after:bottom-0 after:h-0.5 after:rounded-full after:bg-action-primary"
|
|
79
|
+
: tone === "muted"
|
|
80
|
+
? "text-on-surface-muted hover:text-on-surface"
|
|
81
|
+
: "text-on-surface-secondary hover:text-on-surface", className), children: [link.label, link.dot && _jsx("span", { className: "size-2 shrink-0 rounded-full bg-primary-400" }), link.hasDropdown && _jsx(Icon, { name: "chevron-down", size: "xs" })] }));
|
|
82
|
+
}
|
|
83
|
+
function NavLinks({ links, large, gap = NAV_GAP, className, }) {
|
|
84
|
+
if (links.length === 0)
|
|
85
|
+
return null;
|
|
86
|
+
return (_jsx("div", { className: cn("flex items-center", gap, className), children: links.map((link, i) => (_jsx(NavLink, { link: link, large: large }, `${link.label}-${i}`))) }));
|
|
87
|
+
}
|
|
88
|
+
/** Same link component, stacked — so an href-only destination is still an anchor. */
|
|
89
|
+
function StackedNavLinks({ links, tone, onNavigate, }) {
|
|
90
|
+
if (links.length === 0)
|
|
91
|
+
return null;
|
|
92
|
+
return (_jsx("div", { className: "flex flex-col gap-1", children: links.map((link, i) => (_jsx(NavLink, { link: link, tone: tone, onNavigate: onNavigate, className: cn("justify-between rounded-lg px-3 py-2.5 text-left after:hidden hover:bg-grey-75", link.active && "bg-primary-50 hover:bg-primary-50") }, `${link.label}-${i}`))) }));
|
|
93
|
+
}
|
|
94
|
+
// ─── Component ───────────────────────────────────────────────────────
|
|
95
|
+
export function HeaderBlock({ variant = 1, logo, links = [], rightLinks = [], actions = [], announcement, searchPlaceholder = "Search for components...", onSearch, switcher, secondaryLinks = [], navLabel = "Main", secondaryNavLabel = "Secondary", className, }) {
|
|
96
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
97
|
+
const [internalActiveTab, setActiveTab] = useState(switcher?.defaultActiveIndex ?? 0);
|
|
98
|
+
/** An index outside the tab list would leave the group with nothing selected. */
|
|
99
|
+
const clampTab = (index) => Math.min(Math.max(index, 0), Math.max((switcher?.tabs.length ?? 1) - 1, 0));
|
|
100
|
+
const isSwitcherControlled = typeof switcher?.activeIndex === "number";
|
|
101
|
+
const activeTab = clampTab(isSwitcherControlled ? switcher.activeIndex : internalActiveTab);
|
|
102
|
+
/** One place decides both modes, so they can never drift apart. */
|
|
103
|
+
const selectTab = (index) => {
|
|
104
|
+
if (index === activeTab)
|
|
105
|
+
return; // not a change; raise nothing
|
|
106
|
+
if (!isSwitcherControlled)
|
|
107
|
+
setActiveTab(index);
|
|
108
|
+
switcher?.onChange?.(index);
|
|
109
|
+
};
|
|
110
|
+
const [menuOpen, setMenuOpen] = useState(false);
|
|
111
|
+
const menuId = useId();
|
|
112
|
+
const toggleRef = useRef(null);
|
|
113
|
+
const isDark = variant === 4 || variant === 8;
|
|
114
|
+
const isLargeLinks = [3, 4, 5, 6, 9, 10, 11].includes(variant);
|
|
115
|
+
const isRoundedButtons = [5, 6, 7, 8, 9, 10].includes(variant);
|
|
116
|
+
const hasSearch = variant === 9;
|
|
117
|
+
const hasSwitcher = (variant === 10 || variant === 11) && !!switcher;
|
|
118
|
+
const tier = TIER[VARIANT_TIER[variant]];
|
|
119
|
+
const rowPadding = ROW_PADDING;
|
|
120
|
+
/** Nothing to collapse means nothing to toggle: do not render an inert control. */
|
|
121
|
+
const hasMenuContent = links.length > 0 ||
|
|
122
|
+
rightLinks.length > 0 ||
|
|
123
|
+
secondaryLinks.length > 0 ||
|
|
124
|
+
actions.length > 0 ||
|
|
125
|
+
hasSearch ||
|
|
126
|
+
hasSwitcher;
|
|
127
|
+
const closeMenu = () => setMenuOpen(false);
|
|
128
|
+
function handleKeyDown(event) {
|
|
129
|
+
if (event.key !== "Escape" || !menuOpen)
|
|
130
|
+
return;
|
|
131
|
+
setMenuOpen(false);
|
|
132
|
+
toggleRef.current?.focus();
|
|
133
|
+
}
|
|
134
|
+
// ─── Render a single action button ─────────────────────────────
|
|
135
|
+
function renderAction(action, index, onNavigate) {
|
|
136
|
+
const Tag = action.href ? "a" : "button";
|
|
137
|
+
const actionVariant = action.variant ?? "primary";
|
|
138
|
+
const isLargeButton = [3, 4, 5, 11].includes(variant);
|
|
139
|
+
return (_jsx(Tag, { ...(action.href ? { href: action.href } : { type: "button" }), onClick: () => {
|
|
140
|
+
action.onClick?.();
|
|
141
|
+
onNavigate?.();
|
|
142
|
+
}, className: cn("inline-flex min-h-11 cursor-pointer items-center justify-center whitespace-nowrap px-4 py-2 text-sm font-semibold transition-colors duration-150 motion-reduce:transition-none", FOCUS_RING, isRoundedButtons ? "rounded-2xl" : "rounded-lg", actionVariant === "text" &&
|
|
143
|
+
"rounded-lg text-on-surface-secondary hover:bg-grey-75 hover:text-on-surface active:bg-grey-100", actionVariant === "secondary" &&
|
|
144
|
+
"border border-surface-border-strong bg-surface text-on-surface hover:bg-grey-75 active:bg-grey-100", actionVariant === "secondary" &&
|
|
145
|
+
variant === 5 &&
|
|
146
|
+
"border-transparent bg-primary-50 text-action-primary-text hover:bg-primary-75", actionVariant === "secondary" &&
|
|
147
|
+
variant === 8 &&
|
|
148
|
+
"border-transparent bg-grey-100 hover:bg-grey-200", actionVariant === "primary" &&
|
|
149
|
+
"bg-action-primary text-white hover:bg-action-primary-hover active:bg-action-primary-hover", actionVariant !== "text" && isLargeButton && "px-5 text-base", actionVariant === "primary" && (variant === 3 || variant === 4) && "rounded-full"), children: action.label }, index));
|
|
150
|
+
}
|
|
151
|
+
// ─── Actions section ───────────────────────────────────────────
|
|
152
|
+
const actionsSection = actions.length > 0 && (_jsx("div", { className: "flex shrink-0 items-center gap-2 @min-[1140px]:gap-3", children: actions.map((a, i) => renderAction(a, i)) }));
|
|
153
|
+
// ─── Search ────────────────────────────────────────────────────
|
|
154
|
+
function renderSearch(wrapperClassName) {
|
|
155
|
+
if (!hasSearch)
|
|
156
|
+
return null;
|
|
157
|
+
return (_jsx(Input, { size: "sm", type: "search", "aria-label": searchPlaceholder, placeholder: searchPlaceholder, leadingIcon: "search", value: searchQuery, onChange: (e) => {
|
|
158
|
+
setSearchQuery(e.target.value);
|
|
159
|
+
onSearch?.(e.target.value);
|
|
160
|
+
}, wrapperClassName: wrapperClassName }));
|
|
161
|
+
}
|
|
162
|
+
// ─── Switcher ──────────────────────────────────────────────────
|
|
163
|
+
function renderSwitcher(className) {
|
|
164
|
+
if (!switcher || switcher.tabs.length === 0)
|
|
165
|
+
return null;
|
|
166
|
+
const switcherLabel = switcher.label ?? "Workspace";
|
|
167
|
+
if (variant === 11) {
|
|
168
|
+
// v11: pill-style tabs
|
|
169
|
+
return (_jsx("div", { role: "group", "aria-label": switcherLabel, className: cn("flex items-center gap-2", className), children: switcher.tabs.map((tab, i) => (_jsx("button", { type: "button", "aria-pressed": i === activeTab, onClick: () => selectTab(i), className: cn("cursor-pointer rounded-lg px-4 py-2 text-sm font-semibold whitespace-nowrap", FOCUS_RING, i === activeTab
|
|
170
|
+
? "bg-primary-50 text-action-primary-text"
|
|
171
|
+
: "text-grey-500 hover:text-grey-700"), children: tab }, tab))) }));
|
|
172
|
+
}
|
|
173
|
+
// v10: segmented control. The selected chip is a raised surface rather than a
|
|
174
|
+
// hard-coded white one, so it follows the document's mode.
|
|
175
|
+
return (_jsx("div", { role: "group", "aria-label": switcherLabel, className: cn("flex items-center", className), children: switcher.tabs.map((tab, i) => (_jsx("button", { type: "button", "aria-pressed": i === activeTab, onClick: () => selectTab(i), className: cn("cursor-pointer px-4 py-2.5 text-sm whitespace-nowrap", FOCUS_RING, i === 0 && "rounded-l-lg", i === switcher.tabs.length - 1 && "rounded-r-lg", i === activeTab
|
|
176
|
+
? "border border-surface-border-strong bg-surface font-semibold text-grey-900"
|
|
177
|
+
: "bg-grey-200 font-medium text-grey-600"), children: tab }, tab))) }));
|
|
178
|
+
}
|
|
179
|
+
// ─── Pill nav (variants 3, 4) ──────────────────────────────────
|
|
180
|
+
function renderPillNav() {
|
|
181
|
+
return (_jsx("div", { className: cn("flex items-center rounded-full px-6 py-1 @min-[1140px]:px-8", PILL_GAP, isDark ? "bg-[#292424]" : "bg-grey-75"), children: links.map((link, i) => (_jsx(NavLink, { link: link, large: true }, `${link.label}-${i}`))) }));
|
|
182
|
+
}
|
|
183
|
+
// ─── Collapsed menu toggle ─────────────────────────────────────
|
|
184
|
+
function renderMenuToggle() {
|
|
185
|
+
if (!hasMenuContent)
|
|
186
|
+
return null;
|
|
187
|
+
return (_jsx("button", { ref: toggleRef, type: "button", onClick: () => setMenuOpen((open) => !open), "aria-expanded": menuOpen, "aria-controls": menuId, "aria-label": menuOpen ? "Close menu" : "Open menu", className: cn("flex size-11 shrink-0 cursor-pointer items-center justify-center rounded-lg border border-surface-border-strong text-on-surface-secondary transition-colors hover:bg-grey-75 hover:text-on-surface motion-reduce:transition-none", FOCUS_RING, tier.collapsed), children: _jsx(Icon, { name: menuOpen ? "multiply" : "list", size: "md" }) }));
|
|
188
|
+
}
|
|
189
|
+
// ─── Collapsed menu ────────────────────────────────────────────
|
|
190
|
+
/**
|
|
191
|
+
* Always in the DOM so `aria-controls` resolves to a real element, and carrying the
|
|
192
|
+
* same destinations, search, switcher and actions the expanded row has.
|
|
193
|
+
*/
|
|
194
|
+
function renderMenu() {
|
|
195
|
+
if (!hasMenuContent)
|
|
196
|
+
return null;
|
|
197
|
+
const hasNavContent = links.length > 0 || rightLinks.length > 0 || secondaryLinks.length > 0;
|
|
198
|
+
return (_jsxs("div", { id: menuId, className: cn("flex flex-col gap-4 border-t border-surface-border bg-surface px-4 pt-4 pb-5 @min-[640px]:px-6", tier.collapsed, !menuOpen && "hidden"), children: [renderSearch("w-full"), hasSwitcher && renderSwitcher("w-full flex-wrap"), hasNavContent && (_jsxs("nav", { "aria-label": "Menu", className: "flex flex-col gap-3", children: [_jsx(StackedNavLinks, { links: links, onNavigate: closeMenu }), rightLinks.length > 0 && links.length > 0 && (_jsx("div", { className: "h-px w-full bg-surface-border" })), _jsx(StackedNavLinks, { links: rightLinks, onNavigate: closeMenu }), secondaryLinks.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { className: "h-px w-full bg-surface-border" }), _jsx(StackedNavLinks, { links: secondaryLinks, tone: "muted", onNavigate: closeMenu })] }))] })), actions.length > 0 && (_jsx("div", { className: "flex flex-col gap-2 border-t border-surface-border pt-4", children: actions.map((action, i) => renderAction(action, i, closeMenu)) }))] }));
|
|
199
|
+
}
|
|
200
|
+
const rootProps = {
|
|
201
|
+
className: cn("@container flex w-full flex-col border-b border-surface-border bg-surface", isDark && DARK_ISLAND, className),
|
|
202
|
+
onKeyDown: handleKeyDown,
|
|
203
|
+
};
|
|
204
|
+
// ═══════════════════════════════════════════════════════════════
|
|
205
|
+
// VARIANT 11: Double-row header
|
|
206
|
+
// ═══════════════════════════════════════════════════════════════
|
|
207
|
+
if (variant === 11) {
|
|
208
|
+
return (_jsxs("header", { ...rootProps, children: [_jsxs("div", { className: cn("flex items-center justify-between", rowPadding), children: [_jsx("div", { className: tier.block, children: renderSwitcher() }), secondaryLinks.length > 0 && (_jsx("nav", { "aria-label": secondaryNavLabel, className: cn(tier.row, "items-center", NAV_GAP), children: secondaryLinks.map((link, i) => (_jsx(NavLink, { link: link, tone: "muted" }, `${link.label}-${i}`))) })), _jsx("div", { className: cn("min-w-0 flex-1", tier.collapsed), children: logo }), renderMenuToggle()] }), _jsx("div", { className: "h-px w-full bg-surface-border" }), _jsxs("div", { className: cn(tier.row, "items-center justify-between", rowPadding), children: [_jsxs("div", { className: "flex min-w-0 items-center gap-6 @min-[1140px]:gap-10", children: [logo, links.length > 0 && (_jsx("nav", { "aria-label": navLabel, children: _jsx(NavLinks, { links: links, large: true, gap: NAV_GAP }) }))] }), actionsSection] }), renderMenu()] }));
|
|
209
|
+
}
|
|
210
|
+
// ═══════════════════════════════════════════════════════════════
|
|
211
|
+
// VARIANTS 7, 8: Centered logo layout
|
|
212
|
+
// Left links | Logo (center) | Right links + Actions
|
|
213
|
+
// ═══════════════════════════════════════════════════════════════
|
|
214
|
+
if (variant === 7 || variant === 8) {
|
|
215
|
+
return (_jsxs("header", { ...rootProps, children: [_jsxs("div", { className: cn("flex w-full items-center justify-between gap-4", variant === 7
|
|
216
|
+
? "@min-[1060px]:grid @min-[1060px]:grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)]"
|
|
217
|
+
: "@min-[1280px]:grid @min-[1280px]:grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)]", rowPadding), children: [_jsx("div", { className: cn(tier.block, "min-w-0"), children: links.length > 0 && (_jsx("nav", { "aria-label": navLabel, children: _jsx(NavLinks, { links: links }) })) }), _jsx("div", { className: "min-w-0", children: logo }), _jsxs("div", { className: "flex items-center justify-self-end gap-4 @min-[1140px]:gap-6", children: [_jsxs("div", { className: cn(tier.row, "items-center gap-4 @min-[1140px]:gap-6"), children: [rightLinks.length > 0 && (_jsx("nav", { "aria-label": secondaryNavLabel, children: _jsx(NavLinks, { links: rightLinks }) })), actionsSection] }), renderMenuToggle()] })] }), renderMenu()] }));
|
|
218
|
+
}
|
|
219
|
+
// ═══════════════════════════════════════════════════════════════
|
|
220
|
+
// ALL OTHER VARIANTS (1–6, 9, 10)
|
|
221
|
+
// Logo (left) | Links (center) | Actions (right)
|
|
222
|
+
// ═══════════════════════════════════════════════════════════════
|
|
223
|
+
return (_jsxs("header", { ...rootProps, children: [variant === 1 && announcement && (_jsxs("div", { className: "flex w-full flex-wrap items-center justify-center gap-x-3 gap-y-1 bg-[#290b00] px-4 py-2.5 text-center", children: [_jsx("span", { className: "text-xs text-white", children: announcement.text }), announcement.linkLabel && (_jsx("button", { type: "button", onClick: announcement.onLinkClick, className: cn("cursor-pointer rounded text-xs font-semibold text-warning-400", FOCUS_RING), children: announcement.linkLabel }))] })), _jsxs("div", { className: cn("flex w-full items-center justify-between gap-4", rowPadding), children: [_jsxs("div", { className: cn("flex items-center gap-4 @min-[1140px]:gap-10",
|
|
224
|
+
// The search field is the one element allowed to absorb the slack, so it
|
|
225
|
+
// shrinks instead of pinning the row to a 375px minimum.
|
|
226
|
+
hasSearch ? "min-w-0 flex-1" : "shrink-0"), children: [logo, renderSearch(cn(tier.block, "min-w-[200px] max-w-[375px] flex-1")), hasSwitcher && _jsx("div", { className: tier.block, children: renderSwitcher() })] }), (links.length > 0 || variant === 3 || variant === 4) && (_jsx("nav", { "aria-label": navLabel, className: tier.block, children: variant === 3 || variant === 4 ? (renderPillNav()) : (_jsx(NavLinks, { links: links, large: isLargeLinks })) })), _jsxs("div", { className: "flex shrink-0 items-center gap-4 @min-[1140px]:gap-6", children: [rightLinks.length > 0 && (_jsx("nav", { "aria-label": secondaryNavLabel, className: tier.block, children: _jsx(NavLinks, { links: rightLinks, large: isLargeLinks }) })), _jsx("div", { className: cn(tier.row, "items-center"), children: actionsSection }), renderMenuToggle()] })] }), renderMenu()] }));
|
|
227
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KpiOverviewBlock = KpiOverviewBlock;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const cn_1 = require("../utils/cn.cjs");
|
|
7
|
+
const Alert_1 = require("../components/Alert/index.cjs");
|
|
8
|
+
const Button_1 = require("../components/Button/index.cjs");
|
|
9
|
+
const Icon_1 = require("../components/Icon/index.cjs");
|
|
10
|
+
const Spinner_1 = require("../components/Spinner/index.cjs");
|
|
11
|
+
/* ─── Change badge ───────────────────────────────────────────────────── */
|
|
12
|
+
const sentimentStyles = {
|
|
13
|
+
positive: "bg-success-50 text-success-700",
|
|
14
|
+
negative: "bg-error-50 text-error-700",
|
|
15
|
+
neutral: "bg-grey-100 text-grey-700",
|
|
16
|
+
};
|
|
17
|
+
const directionIcon = {
|
|
18
|
+
up: "arrow-up",
|
|
19
|
+
down: "arrow-down",
|
|
20
|
+
flat: "minus",
|
|
21
|
+
};
|
|
22
|
+
const directionText = {
|
|
23
|
+
up: "increased by",
|
|
24
|
+
down: "decreased by",
|
|
25
|
+
flat: "unchanged at",
|
|
26
|
+
};
|
|
27
|
+
function ChangeBadge({ change, comparisonLabel }) {
|
|
28
|
+
const sentiment = change.sentiment ?? "neutral";
|
|
29
|
+
return ((0, jsx_runtime_1.jsxs)("span", { className: (0, cn_1.cn)("inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-body-xs font-medium", sentimentStyles[sentiment]), children: [(0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: directionIcon[change.direction], size: "xs" }), (0, jsx_runtime_1.jsx)("span", { className: "sr-only", children: directionText[change.direction] }), (0, jsx_runtime_1.jsx)("span", { children: change.label }), (0, jsx_runtime_1.jsxs)("span", { className: "sr-only", children: ["compared with ", comparisonLabel] })] }));
|
|
30
|
+
}
|
|
31
|
+
/* ─── Tile ───────────────────────────────────────────────────────────── */
|
|
32
|
+
function MetricTrend({ label, trend }) {
|
|
33
|
+
if (trend.values.some((value) => !Number.isFinite(value)))
|
|
34
|
+
return null;
|
|
35
|
+
const low = Math.min(...trend.values);
|
|
36
|
+
const range = Math.max(...trend.values) - low || 1;
|
|
37
|
+
const points = trend.values
|
|
38
|
+
.map((value, index) => `${2 + (index / (trend.values.length - 1)) * 296},${44 - ((value - low) / range) * 40}`)
|
|
39
|
+
.join(" ");
|
|
40
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "relative", children: [(0, jsx_runtime_1.jsx)("svg", { viewBox: "0 0 300 48", preserveAspectRatio: "none", "aria-hidden": "true", className: "h-12 w-full text-action-primary-text", children: (0, jsx_runtime_1.jsx)("polyline", { points: points, fill: "none", stroke: "currentColor", strokeWidth: "2", vectorEffect: "non-scaling-stroke" }) }), (0, jsx_runtime_1.jsxs)("table", { className: "sr-only", children: [(0, jsx_runtime_1.jsxs)("caption", { children: [label, " trend"] }), (0, jsx_runtime_1.jsx)("thead", { children: (0, jsx_runtime_1.jsxs)("tr", { children: [(0, jsx_runtime_1.jsx)("th", { scope: "col", children: "Period" }), (0, jsx_runtime_1.jsx)("th", { scope: "col", children: "Value" })] }) }), (0, jsx_runtime_1.jsx)("tbody", { children: trend.values.map((value, index) => ((0, jsx_runtime_1.jsxs)("tr", { children: [(0, jsx_runtime_1.jsx)("th", { scope: "row", children: trend.labels[index] ?? `Point ${index + 1}` }), (0, jsx_runtime_1.jsx)("td", { children: value })] }, index))) })] })] }));
|
|
41
|
+
}
|
|
42
|
+
function MetricBody({ metric, comparisonLabel, labelId, }) {
|
|
43
|
+
if (metric.unavailableReason) {
|
|
44
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "flex min-w-0 flex-col gap-2", children: [(0, jsx_runtime_1.jsx)("span", { id: labelId, className: "text-body-sm font-medium text-grey-600", children: metric.label }), (0, jsx_runtime_1.jsx)("span", { className: "text-h6 font-semibold text-grey-600", children: "Not available" }), (0, jsx_runtime_1.jsx)("p", { className: "text-body-xs text-grey-600", children: metric.unavailableReason })] }));
|
|
45
|
+
}
|
|
46
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "flex min-w-0 flex-col gap-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-start justify-between gap-3", children: [(0, jsx_runtime_1.jsx)("span", { id: labelId, className: "min-w-0 text-body-sm font-medium text-grey-600", children: metric.label }), metric.icon && ((0, jsx_runtime_1.jsx)("span", { className: "flex size-8 shrink-0 items-center justify-center rounded-lg border border-surface-border text-grey-600", children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: metric.icon, size: "sm" }) }))] }), (0, jsx_runtime_1.jsx)("p", { className: "text-h5 font-semibold break-words text-grey-900", children: metric.value }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [metric.change && (0, jsx_runtime_1.jsx)(ChangeBadge, { change: metric.change, comparisonLabel: comparisonLabel }), metric.comparisonValue ? ((0, jsx_runtime_1.jsxs)("span", { className: "text-body-xs text-grey-600", children: ["from ", metric.comparisonValue, " in ", comparisonLabel] })) : ((0, jsx_runtime_1.jsxs)("span", { className: "text-body-xs text-grey-600", children: ["No comparable figure for ", comparisonLabel] }))] }), metric.trend && metric.trend.values.length > 1 && ((0, jsx_runtime_1.jsx)(MetricTrend, { label: metric.label, trend: metric.trend })), metric.description && (0, jsx_runtime_1.jsx)("p", { className: "text-body-sm text-grey-600", children: metric.description })] }));
|
|
47
|
+
}
|
|
48
|
+
/* ─── Component ──────────────────────────────────────────────────────── */
|
|
49
|
+
function KpiOverviewBlock({ title = "Performance overview", description, headingLevel = "h2", period, metrics, periodOptions, selectedPeriodId, onPeriodChange, periodSelectLabel = "Reporting period", status = "idle", errorMessage, onRetry, onSelectMetric, emptyTitle = "No metrics selected", emptyDescription = "Choose the measures you want to follow and they will appear here.", footer, loadingPlaceholderCount = 4, className, }) {
|
|
50
|
+
const uid = (0, react_1.useId)();
|
|
51
|
+
const titleId = `${uid}-title`;
|
|
52
|
+
const periodId = `${uid}-period`;
|
|
53
|
+
const periodSelectId = `${uid}-period-select`;
|
|
54
|
+
const Heading = headingLevel;
|
|
55
|
+
const showPeriodSelector = Boolean(periodOptions && periodOptions.length > 0 && selectedPeriodId && onPeriodChange);
|
|
56
|
+
// `relative` gives visually hidden, absolutely positioned text inside a tile
|
|
57
|
+
// a containing block, so it can never escape and widen the document.
|
|
58
|
+
const tileClass = "relative flex h-full min-w-0 flex-col gap-3 rounded-12 border border-surface-border bg-surface p-4 text-left";
|
|
59
|
+
return ((0, jsx_runtime_1.jsxs)("section", { "aria-labelledby": titleId, className: (0, cn_1.cn)("@container flex w-full flex-col gap-4", className), children: [(0, jsx_runtime_1.jsxs)("header", { className: "flex flex-col gap-3 @min-[620px]:flex-row @min-[620px]:items-end @min-[620px]:justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex min-w-0 flex-col gap-1", children: [(0, jsx_runtime_1.jsx)(Heading, { id: titleId, className: "text-h6 font-semibold text-grey-900", children: title }), (0, jsx_runtime_1.jsxs)("p", { id: periodId, className: "text-body-sm text-grey-600", children: [period.label, " \u00B7 compared with ", period.comparisonLabel] }), description && (0, jsx_runtime_1.jsx)("p", { className: "text-body-sm text-grey-600", children: description })] }), showPeriodSelector && ((0, jsx_runtime_1.jsxs)("div", { className: "flex min-w-0 flex-col gap-1", children: [(0, jsx_runtime_1.jsx)("label", { htmlFor: periodSelectId, className: "text-sm font-medium leading-[1.45] text-grey-900", children: periodSelectLabel }), (0, jsx_runtime_1.jsx)("select", { id: periodSelectId, value: selectedPeriodId, onChange: (event) => onPeriodChange?.(event.target.value), className: (0, cn_1.cn)("h-10 w-full rounded-lg border border-grey-300 bg-surface px-3 text-sm text-grey-900 @min-[620px]:w-auto", "transition-colors hover:border-primary-100", "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-action-primary-text"), children: periodOptions?.map((option) => ((0, jsx_runtime_1.jsx)("option", { value: option.id, children: option.label }, option.id))) })] }))] }), status === "error" ? ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-3", children: [(0, jsx_runtime_1.jsx)(Alert_1.Alert, { state: "error", icon: "info-triangle", role: "alert", title: "These metrics could not be loaded", description: errorMessage ?? "The reporting service did not respond. Your filters are unchanged.", className: "bg-surface dark:bg-surface" }), onRetry && ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)(Button_1.Button, { type: "button", variant: "secondary", size: "sm", onClick: onRetry, children: "Try again" }) }))] })) : status === "loading" ? ((0, jsx_runtime_1.jsxs)("div", { "aria-busy": "true", className: "flex flex-col gap-3", children: [(0, jsx_runtime_1.jsxs)("output", { className: "flex items-center gap-2 pl-1 text-body-sm text-grey-600", children: [(0, jsx_runtime_1.jsx)(Spinner_1.Spinner, { size: "xs" }), "Loading metrics for ", period.label, "\u2026"] }), (0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-1 gap-4 @min-[560px]:grid-cols-2 @min-[1000px]:grid-cols-4", children: Array.from({ length: loadingPlaceholderCount }, (_, index) => ((0, jsx_runtime_1.jsxs)("div", { "aria-hidden": "true", className: (0, cn_1.cn)(tileClass, "gap-3"), children: [(0, jsx_runtime_1.jsx)("span", { className: "h-4 w-2/3 rounded bg-grey-100" }), (0, jsx_runtime_1.jsx)("span", { className: "h-7 w-1/2 rounded bg-grey-100" }), (0, jsx_runtime_1.jsx)("span", { className: "h-4 w-full rounded bg-grey-100" })] }, index))) })] })) : metrics.length === 0 ? ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-start gap-2 rounded-12 border border-dashed border-surface-border-strong bg-surface p-6", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-body-md font-semibold text-grey-900", children: emptyTitle }), (0, jsx_runtime_1.jsx)("p", { className: "text-body-sm text-grey-600", children: emptyDescription })] })) : ((0, jsx_runtime_1.jsx)("ul", { role: "list", "aria-describedby": periodId, className: "grid list-none grid-cols-1 gap-4 p-0 @min-[560px]:grid-cols-2 @min-[1000px]:grid-cols-4", children: metrics.map((metric) => {
|
|
60
|
+
const labelId = `${uid}-metric-${metric.id}`;
|
|
61
|
+
return ((0, jsx_runtime_1.jsxs)("li", { className: (0, cn_1.cn)(tileClass, "min-w-0"), children: [(0, jsx_runtime_1.jsx)(MetricBody, { metric: metric, comparisonLabel: period.comparisonLabel, labelId: labelId }), onSelectMetric && !metric.unavailableReason && ((0, jsx_runtime_1.jsxs)("button", { type: "button", onClick: () => onSelectMetric(metric.id), className: "mt-auto inline-flex cursor-pointer items-center gap-1 self-start rounded pt-1 text-body-xs font-semibold text-action-primary-text hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-action-primary-text", children: ["View details ", (0, jsx_runtime_1.jsxs)("span", { className: "sr-only", children: ["for ", metric.label] }), (0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: "chevron-right", size: "xs" })] }))] }, metric.id));
|
|
62
|
+
}) })), footer && (0, jsx_runtime_1.jsx)("div", { className: "flex flex-wrap items-center gap-3", children: footer })] }));
|
|
63
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useId } from "react";
|
|
3
|
+
import { cn } from "../utils/cn.js";
|
|
4
|
+
import { Alert } from "../components/Alert/index.js";
|
|
5
|
+
import { Button } from "../components/Button/index.js";
|
|
6
|
+
import { Icon } from "../components/Icon/index.js";
|
|
7
|
+
import { Spinner } from "../components/Spinner/index.js";
|
|
8
|
+
/* ─── Change badge ───────────────────────────────────────────────────── */
|
|
9
|
+
const sentimentStyles = {
|
|
10
|
+
positive: "bg-success-50 text-success-700",
|
|
11
|
+
negative: "bg-error-50 text-error-700",
|
|
12
|
+
neutral: "bg-grey-100 text-grey-700",
|
|
13
|
+
};
|
|
14
|
+
const directionIcon = {
|
|
15
|
+
up: "arrow-up",
|
|
16
|
+
down: "arrow-down",
|
|
17
|
+
flat: "minus",
|
|
18
|
+
};
|
|
19
|
+
const directionText = {
|
|
20
|
+
up: "increased by",
|
|
21
|
+
down: "decreased by",
|
|
22
|
+
flat: "unchanged at",
|
|
23
|
+
};
|
|
24
|
+
function ChangeBadge({ change, comparisonLabel }) {
|
|
25
|
+
const sentiment = change.sentiment ?? "neutral";
|
|
26
|
+
return (_jsxs("span", { className: cn("inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-body-xs font-medium", sentimentStyles[sentiment]), children: [_jsx(Icon, { name: directionIcon[change.direction], size: "xs" }), _jsx("span", { className: "sr-only", children: directionText[change.direction] }), _jsx("span", { children: change.label }), _jsxs("span", { className: "sr-only", children: ["compared with ", comparisonLabel] })] }));
|
|
27
|
+
}
|
|
28
|
+
/* ─── Tile ───────────────────────────────────────────────────────────── */
|
|
29
|
+
function MetricTrend({ label, trend }) {
|
|
30
|
+
if (trend.values.some((value) => !Number.isFinite(value)))
|
|
31
|
+
return null;
|
|
32
|
+
const low = Math.min(...trend.values);
|
|
33
|
+
const range = Math.max(...trend.values) - low || 1;
|
|
34
|
+
const points = trend.values
|
|
35
|
+
.map((value, index) => `${2 + (index / (trend.values.length - 1)) * 296},${44 - ((value - low) / range) * 40}`)
|
|
36
|
+
.join(" ");
|
|
37
|
+
return (_jsxs("div", { className: "relative", children: [_jsx("svg", { viewBox: "0 0 300 48", preserveAspectRatio: "none", "aria-hidden": "true", className: "h-12 w-full text-action-primary-text", children: _jsx("polyline", { points: points, fill: "none", stroke: "currentColor", strokeWidth: "2", vectorEffect: "non-scaling-stroke" }) }), _jsxs("table", { className: "sr-only", children: [_jsxs("caption", { children: [label, " trend"] }), _jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "Period" }), _jsx("th", { scope: "col", children: "Value" })] }) }), _jsx("tbody", { children: trend.values.map((value, index) => (_jsxs("tr", { children: [_jsx("th", { scope: "row", children: trend.labels[index] ?? `Point ${index + 1}` }), _jsx("td", { children: value })] }, index))) })] })] }));
|
|
38
|
+
}
|
|
39
|
+
function MetricBody({ metric, comparisonLabel, labelId, }) {
|
|
40
|
+
if (metric.unavailableReason) {
|
|
41
|
+
return (_jsxs("div", { className: "flex min-w-0 flex-col gap-2", children: [_jsx("span", { id: labelId, className: "text-body-sm font-medium text-grey-600", children: metric.label }), _jsx("span", { className: "text-h6 font-semibold text-grey-600", children: "Not available" }), _jsx("p", { className: "text-body-xs text-grey-600", children: metric.unavailableReason })] }));
|
|
42
|
+
}
|
|
43
|
+
return (_jsxs("div", { className: "flex min-w-0 flex-col gap-3", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsx("span", { id: labelId, className: "min-w-0 text-body-sm font-medium text-grey-600", children: metric.label }), metric.icon && (_jsx("span", { className: "flex size-8 shrink-0 items-center justify-center rounded-lg border border-surface-border text-grey-600", children: _jsx(Icon, { name: metric.icon, size: "sm" }) }))] }), _jsx("p", { className: "text-h5 font-semibold break-words text-grey-900", children: metric.value }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [metric.change && _jsx(ChangeBadge, { change: metric.change, comparisonLabel: comparisonLabel }), metric.comparisonValue ? (_jsxs("span", { className: "text-body-xs text-grey-600", children: ["from ", metric.comparisonValue, " in ", comparisonLabel] })) : (_jsxs("span", { className: "text-body-xs text-grey-600", children: ["No comparable figure for ", comparisonLabel] }))] }), metric.trend && metric.trend.values.length > 1 && (_jsx(MetricTrend, { label: metric.label, trend: metric.trend })), metric.description && _jsx("p", { className: "text-body-sm text-grey-600", children: metric.description })] }));
|
|
44
|
+
}
|
|
45
|
+
/* ─── Component ──────────────────────────────────────────────────────── */
|
|
46
|
+
export function KpiOverviewBlock({ title = "Performance overview", description, headingLevel = "h2", period, metrics, periodOptions, selectedPeriodId, onPeriodChange, periodSelectLabel = "Reporting period", status = "idle", errorMessage, onRetry, onSelectMetric, emptyTitle = "No metrics selected", emptyDescription = "Choose the measures you want to follow and they will appear here.", footer, loadingPlaceholderCount = 4, className, }) {
|
|
47
|
+
const uid = useId();
|
|
48
|
+
const titleId = `${uid}-title`;
|
|
49
|
+
const periodId = `${uid}-period`;
|
|
50
|
+
const periodSelectId = `${uid}-period-select`;
|
|
51
|
+
const Heading = headingLevel;
|
|
52
|
+
const showPeriodSelector = Boolean(periodOptions && periodOptions.length > 0 && selectedPeriodId && onPeriodChange);
|
|
53
|
+
// `relative` gives visually hidden, absolutely positioned text inside a tile
|
|
54
|
+
// a containing block, so it can never escape and widen the document.
|
|
55
|
+
const tileClass = "relative flex h-full min-w-0 flex-col gap-3 rounded-12 border border-surface-border bg-surface p-4 text-left";
|
|
56
|
+
return (_jsxs("section", { "aria-labelledby": titleId, className: cn("@container flex w-full flex-col gap-4", className), children: [_jsxs("header", { className: "flex flex-col gap-3 @min-[620px]:flex-row @min-[620px]:items-end @min-[620px]:justify-between", children: [_jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [_jsx(Heading, { id: titleId, className: "text-h6 font-semibold text-grey-900", children: title }), _jsxs("p", { id: periodId, className: "text-body-sm text-grey-600", children: [period.label, " \u00B7 compared with ", period.comparisonLabel] }), description && _jsx("p", { className: "text-body-sm text-grey-600", children: description })] }), showPeriodSelector && (_jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [_jsx("label", { htmlFor: periodSelectId, className: "text-sm font-medium leading-[1.45] text-grey-900", children: periodSelectLabel }), _jsx("select", { id: periodSelectId, value: selectedPeriodId, onChange: (event) => onPeriodChange?.(event.target.value), className: cn("h-10 w-full rounded-lg border border-grey-300 bg-surface px-3 text-sm text-grey-900 @min-[620px]:w-auto", "transition-colors hover:border-primary-100", "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-action-primary-text"), children: periodOptions?.map((option) => (_jsx("option", { value: option.id, children: option.label }, option.id))) })] }))] }), status === "error" ? (_jsxs("div", { className: "flex flex-col gap-3", children: [_jsx(Alert, { state: "error", icon: "info-triangle", role: "alert", title: "These metrics could not be loaded", description: errorMessage ?? "The reporting service did not respond. Your filters are unchanged.", className: "bg-surface dark:bg-surface" }), onRetry && (_jsx("div", { children: _jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: onRetry, children: "Try again" }) }))] })) : status === "loading" ? (_jsxs("div", { "aria-busy": "true", className: "flex flex-col gap-3", children: [_jsxs("output", { className: "flex items-center gap-2 pl-1 text-body-sm text-grey-600", children: [_jsx(Spinner, { size: "xs" }), "Loading metrics for ", period.label, "\u2026"] }), _jsx("div", { className: "grid grid-cols-1 gap-4 @min-[560px]:grid-cols-2 @min-[1000px]:grid-cols-4", children: Array.from({ length: loadingPlaceholderCount }, (_, index) => (_jsxs("div", { "aria-hidden": "true", className: cn(tileClass, "gap-3"), children: [_jsx("span", { className: "h-4 w-2/3 rounded bg-grey-100" }), _jsx("span", { className: "h-7 w-1/2 rounded bg-grey-100" }), _jsx("span", { className: "h-4 w-full rounded bg-grey-100" })] }, index))) })] })) : metrics.length === 0 ? (_jsxs("div", { className: "flex flex-col items-start gap-2 rounded-12 border border-dashed border-surface-border-strong bg-surface p-6", children: [_jsx("p", { className: "text-body-md font-semibold text-grey-900", children: emptyTitle }), _jsx("p", { className: "text-body-sm text-grey-600", children: emptyDescription })] })) : (_jsx("ul", { role: "list", "aria-describedby": periodId, className: "grid list-none grid-cols-1 gap-4 p-0 @min-[560px]:grid-cols-2 @min-[1000px]:grid-cols-4", children: metrics.map((metric) => {
|
|
57
|
+
const labelId = `${uid}-metric-${metric.id}`;
|
|
58
|
+
return (_jsxs("li", { className: cn(tileClass, "min-w-0"), children: [_jsx(MetricBody, { metric: metric, comparisonLabel: period.comparisonLabel, labelId: labelId }), onSelectMetric && !metric.unavailableReason && (_jsxs("button", { type: "button", onClick: () => onSelectMetric(metric.id), className: "mt-auto inline-flex cursor-pointer items-center gap-1 self-start rounded pt-1 text-body-xs font-semibold text-action-primary-text hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-action-primary-text", children: ["View details ", _jsxs("span", { className: "sr-only", children: ["for ", metric.label] }), _jsx(Icon, { name: "chevron-right", size: "xs" })] }))] }, metric.id));
|
|
59
|
+
}) })), footer && _jsx("div", { className: "flex flex-wrap items-center gap-3", children: footer })] }));
|
|
60
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LoginBlock = LoginBlock;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const cn_1 = require("../utils/cn.cjs");
|
|
7
|
+
const Input_1 = require("../components/Input/index.cjs");
|
|
8
|
+
const Button_1 = require("../components/Button/index.cjs");
|
|
9
|
+
const FormControl_1 = require("../components/FormControl/index.cjs");
|
|
10
|
+
const Divider_1 = require("../components/Divider/index.cjs");
|
|
11
|
+
const Icon_1 = require("../components/Icon/index.cjs");
|
|
12
|
+
// ─── Google Icon ──────────────────────────────────────────────────────
|
|
13
|
+
function GoogleIcon() {
|
|
14
|
+
return ((0, jsx_runtime_1.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: [(0, jsx_runtime_1.jsx)("path", { d: "M18.17 8.37H17.5V8.33H10V11.67H14.71C14.02 13.61 12.18 15 10 15C7.24 15 5 12.76 5 10C5 7.24 7.24 5 10 5C11.27 5 12.42 5.48 13.3 6.27L15.67 3.9C14.15 2.49 12.18 1.67 10 1.67C5.4 1.67 1.67 5.4 1.67 10C1.67 14.6 5.4 18.33 10 18.33C14.6 18.33 18.33 14.6 18.33 10C18.33 9.44 18.28 8.9 18.17 8.37Z", fill: "#FFC107" }), (0, jsx_runtime_1.jsx)("path", { d: "M2.63 6.12L5.37 8.13C6.12 6.29 7.91 5 10 5C11.27 5 12.42 5.48 13.3 6.27L15.67 3.9C14.15 2.49 12.18 1.67 10 1.67C6.95 1.67 4.31 3.47 2.63 6.12Z", fill: "#FF3D00" }), (0, jsx_runtime_1.jsx)("path", { d: "M10 18.33C12.13 18.33 14.06 17.55 15.56 16.2L12.96 14.01C12.12 14.63 11.09 15 10 15C7.83 15 5.99 13.62 5.3 11.69L2.58 13.78C4.24 16.51 6.91 18.33 10 18.33Z", fill: "#4CAF50" }), (0, jsx_runtime_1.jsx)("path", { d: "M18.17 8.37H17.5V8.33H10V11.67H14.71C14.38 12.59 13.79 13.38 13 13.96L13 13.96L15.56 16.2C15.37 16.37 18.33 14.17 18.33 10C18.33 9.44 18.28 8.9 18.17 8.37Z", fill: "#1976D2" })] }));
|
|
15
|
+
}
|
|
16
|
+
// ─── Twitter / X Icon ────────────────────────────────────────────────
|
|
17
|
+
function TwitterIcon() {
|
|
18
|
+
return ((0, jsx_runtime_1.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: (0, jsx_runtime_1.jsx)("path", { d: "M15.27 1.58H18.08L11.94 8.66L19.17 18.42H13.51L9.08 12.6L4.01 18.42H1.19L7.79 10.84L0.83 1.58H6.63L10.61 6.88L15.27 1.58ZM14.27 16.68H15.83L5.83 3.18H4.17L14.27 16.68Z", fill: "#1DA1F2" }) }));
|
|
19
|
+
}
|
|
20
|
+
// ─── Component ───────────────────────────────────────────────────────
|
|
21
|
+
function LoginBlock({ variant = "standard", title, subtitle, submitLabel, onForgotPassword, onSubmit, socialProviders, onSignUp, signUpPrompt, signUpLabel, showRememberMe = true, rememberMeLabel = "Remember me", pending = false, pendingLabel = "Signing in…", error, className, }) {
|
|
22
|
+
const [email, setEmail] = (0, react_1.useState)("");
|
|
23
|
+
const [password, setPassword] = (0, react_1.useState)("");
|
|
24
|
+
const [showPassword, setShowPassword] = (0, react_1.useState)(false);
|
|
25
|
+
const [rememberMe, setRememberMe] = (0, react_1.useState)(false);
|
|
26
|
+
// Defaults per variant
|
|
27
|
+
const resolvedTitle = title ?? (variant === "work-email" ? "Sign in with your work email" : "Log In");
|
|
28
|
+
const resolvedSubtitle = subtitle ??
|
|
29
|
+
(variant === "work-email"
|
|
30
|
+
? "Use your work email to sign in to your team workspace"
|
|
31
|
+
: "Enter your credentials to access your account");
|
|
32
|
+
const resolvedSubmitLabel = submitLabel ?? (variant === "work-email" ? "Sign in" : "Log into Account");
|
|
33
|
+
const resolvedSignUpPrompt = signUpPrompt ?? (variant === "work-email" ? "Don't have an account?" : "Are you new here?");
|
|
34
|
+
const resolvedSignUpLabel = signUpLabel ?? (variant === "work-email" ? "Sign up" : "Create Account");
|
|
35
|
+
const resolvedProviders = socialProviders ?? [
|
|
36
|
+
{ name: "Google", icon: (0, jsx_runtime_1.jsx)(GoogleIcon, {}) },
|
|
37
|
+
{ name: "Twitter", icon: (0, jsx_runtime_1.jsx)(TwitterIcon, {}) },
|
|
38
|
+
];
|
|
39
|
+
const handleSubmit = (e) => {
|
|
40
|
+
e.preventDefault();
|
|
41
|
+
// Guard duplicate submission: `disabled` does not stop an implicit
|
|
42
|
+
// Enter-key submit in every browser, and the form may still be reachable
|
|
43
|
+
// while a request is in flight.
|
|
44
|
+
if (pending)
|
|
45
|
+
return;
|
|
46
|
+
onSubmit?.({ email, password, rememberMe });
|
|
47
|
+
};
|
|
48
|
+
const isWorkEmail = variant === "work-email";
|
|
49
|
+
const isCard = variant === "card";
|
|
50
|
+
// Social providers start a competing authentication route, so they follow the
|
|
51
|
+
// pending contract. Provider artwork stays literal brand colour; only the
|
|
52
|
+
// surrounding interface chrome is themeable.
|
|
53
|
+
const providerButtonClass = "flex items-center justify-center gap-4 w-full rounded-md border-[1.5px] border-surface-border-strong bg-surface p-4 text-base font-semibold text-grey-700 hover:bg-grey-50 dark:hover:bg-grey-100 transition-colors cursor-pointer disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-action-primary-text";
|
|
54
|
+
const socialSection = resolvedProviders.length > 0 && ((0, jsx_runtime_1.jsx)("div", { className: "flex flex-col gap-3", children: resolvedProviders.map((provider) => ((0, jsx_runtime_1.jsxs)("button", { type: "button", onClick: provider.onClick, disabled: pending, className: providerButtonClass, children: [(0, jsx_runtime_1.jsx)("span", { className: "shrink-0 size-5", children: provider.icon }), "Continue with ", provider.name] }, provider.name))) }));
|
|
55
|
+
// Password recovery is independent of the remember-me option so every variant
|
|
56
|
+
// that supplies a handler can offer it.
|
|
57
|
+
const forgotPasswordAction = onForgotPassword && ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: onForgotPassword, disabled: pending, className: "rounded text-sm font-medium text-action-primary-text cursor-pointer hover:underline underline-offset-2 disabled:cursor-not-allowed disabled:opacity-50 disabled:no-underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-action-primary-text", children: "Forgot Password?" }));
|
|
58
|
+
const showRememberMeRow = showRememberMe && !isWorkEmail;
|
|
59
|
+
const formContent = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-center gap-2 text-center", children: [(0, jsx_runtime_1.jsx)("h2", { className: "text-h4 font-semibold text-grey-900", children: resolvedTitle }), (0, jsx_runtime_1.jsx)("p", { className: "text-base text-grey-500", children: resolvedSubtitle })] }), isWorkEmail && socialSection && ((0, jsx_runtime_1.jsxs)("div", { className: "mt-10 flex w-full flex-col gap-4", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", onClick: resolvedProviders[0]?.onClick, disabled: pending, className: providerButtonClass, children: [(0, jsx_runtime_1.jsx)("span", { className: "shrink-0 size-5", children: resolvedProviders[0]?.icon }), `Continue with ${resolvedProviders[0]?.name ?? "Google"}`] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "h-px flex-1 bg-surface-border" }), (0, jsx_runtime_1.jsx)("span", { className: "text-sm text-grey-500", children: "OR" }), (0, jsx_runtime_1.jsx)("div", { className: "h-px flex-1 bg-surface-border" })] })] })), (0, jsx_runtime_1.jsxs)("form", { onSubmit: handleSubmit, className: (0, cn_1.cn)("flex flex-col", isWorkEmail ? "gap-6" : "gap-8", !isWorkEmail && "mt-10"), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-6", children: [(0, jsx_runtime_1.jsx)(Input_1.Input, { label: isWorkEmail ? "Email Address" : "EMAIL ADDRESS", placeholder: isWorkEmail ? "" : "Enter Email", size: "lg", type: "email", autoComplete: "email", required: true, disabled: pending, value: email, onChange: (e) => setEmail(e.target.value), trailingIcon: "mail" }), (0, jsx_runtime_1.jsx)(Input_1.Input, { label: "PASSWORD", placeholder: "Enter Password", type: showPassword ? "text" : "password", size: "lg", autoComplete: "current-password", required: true, disabled: pending, value: password, onChange: (e) => setPassword(e.target.value), trailingAction: (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setShowPassword(!showPassword), "aria-label": showPassword ? "Hide password" : "Show password", "aria-pressed": showPassword, className: "flex size-6 items-center justify-center rounded text-grey-500 hover:text-grey-600 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-400", children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: showPassword ? "eye" : "eye-slash", size: "sm" }) }) })] }), (showRememberMeRow || forgotPasswordAction) && ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("flex items-center gap-4", showRememberMeRow ? "justify-between" : "justify-end"), children: [showRememberMeRow && ((0, jsx_runtime_1.jsx)(FormControl_1.Checkbox, { label: rememberMeLabel, checked: rememberMe, disabled: pending, onChange: () => setRememberMe(!rememberMe), wrapperClassName: (0, cn_1.cn)(pending && "cursor-not-allowed opacity-50") })), forgotPasswordAction] }))] }), error && ((0, jsx_runtime_1.jsx)("p", { role: "alert", className: "text-sm text-feedback-error leading-[1.45]", children: error })), (0, jsx_runtime_1.jsx)(Button_1.Button, { type: "submit", variant: "primary", size: "lg", className: "w-full", disabled: pending, "aria-busy": pending || undefined, children: pending ? pendingLabel : resolvedSubmitLabel })] }), !isWorkEmail && socialSection && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(Divider_1.Divider, { variant: "with-label", label: "Or" }), socialSection] })), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-center gap-1", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-sm text-grey-500", children: resolvedSignUpPrompt }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: onSignUp, disabled: pending, className: "rounded text-sm font-medium text-action-primary-text cursor-pointer hover:underline underline-offset-2 disabled:cursor-not-allowed disabled:opacity-50 disabled:no-underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-action-primary-text", children: resolvedSignUpLabel })] })] }));
|
|
60
|
+
// Card variant wraps in a bordered card
|
|
61
|
+
if (isCard) {
|
|
62
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: (0, cn_1.cn)("bg-surface border border-surface-border-strong rounded-10 px-7 py-8 w-full max-w-[432px]", className), children: (0, jsx_runtime_1.jsx)("div", { className: "flex flex-col gap-8", children: formContent }) }));
|
|
63
|
+
}
|
|
64
|
+
// Standard / Work-email: no card wrapper
|
|
65
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: (0, cn_1.cn)("flex flex-col items-center justify-center gap-6 w-full max-w-[400px] px-4 sm:px-0", className), children: formContent }));
|
|
66
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { cn } from "../utils/cn.js";
|
|
4
|
+
import { Input } from "../components/Input/index.js";
|
|
5
|
+
import { Button } from "../components/Button/index.js";
|
|
6
|
+
import { Checkbox } from "../components/FormControl/index.js";
|
|
7
|
+
import { Divider } from "../components/Divider/index.js";
|
|
8
|
+
import { Icon } from "../components/Icon/index.js";
|
|
9
|
+
// ─── Google Icon ──────────────────────────────────────────────────────
|
|
10
|
+
function GoogleIcon() {
|
|
11
|
+
return (_jsxs("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: [_jsx("path", { d: "M18.17 8.37H17.5V8.33H10V11.67H14.71C14.02 13.61 12.18 15 10 15C7.24 15 5 12.76 5 10C5 7.24 7.24 5 10 5C11.27 5 12.42 5.48 13.3 6.27L15.67 3.9C14.15 2.49 12.18 1.67 10 1.67C5.4 1.67 1.67 5.4 1.67 10C1.67 14.6 5.4 18.33 10 18.33C14.6 18.33 18.33 14.6 18.33 10C18.33 9.44 18.28 8.9 18.17 8.37Z", fill: "#FFC107" }), _jsx("path", { d: "M2.63 6.12L5.37 8.13C6.12 6.29 7.91 5 10 5C11.27 5 12.42 5.48 13.3 6.27L15.67 3.9C14.15 2.49 12.18 1.67 10 1.67C6.95 1.67 4.31 3.47 2.63 6.12Z", fill: "#FF3D00" }), _jsx("path", { d: "M10 18.33C12.13 18.33 14.06 17.55 15.56 16.2L12.96 14.01C12.12 14.63 11.09 15 10 15C7.83 15 5.99 13.62 5.3 11.69L2.58 13.78C4.24 16.51 6.91 18.33 10 18.33Z", fill: "#4CAF50" }), _jsx("path", { d: "M18.17 8.37H17.5V8.33H10V11.67H14.71C14.38 12.59 13.79 13.38 13 13.96L13 13.96L15.56 16.2C15.37 16.37 18.33 14.17 18.33 10C18.33 9.44 18.28 8.9 18.17 8.37Z", fill: "#1976D2" })] }));
|
|
12
|
+
}
|
|
13
|
+
// ─── Twitter / X Icon ────────────────────────────────────────────────
|
|
14
|
+
function TwitterIcon() {
|
|
15
|
+
return (_jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: _jsx("path", { d: "M15.27 1.58H18.08L11.94 8.66L19.17 18.42H13.51L9.08 12.6L4.01 18.42H1.19L7.79 10.84L0.83 1.58H6.63L10.61 6.88L15.27 1.58ZM14.27 16.68H15.83L5.83 3.18H4.17L14.27 16.68Z", fill: "#1DA1F2" }) }));
|
|
16
|
+
}
|
|
17
|
+
// ─── Component ───────────────────────────────────────────────────────
|
|
18
|
+
export function LoginBlock({ variant = "standard", title, subtitle, submitLabel, onForgotPassword, onSubmit, socialProviders, onSignUp, signUpPrompt, signUpLabel, showRememberMe = true, rememberMeLabel = "Remember me", pending = false, pendingLabel = "Signing in…", error, className, }) {
|
|
19
|
+
const [email, setEmail] = useState("");
|
|
20
|
+
const [password, setPassword] = useState("");
|
|
21
|
+
const [showPassword, setShowPassword] = useState(false);
|
|
22
|
+
const [rememberMe, setRememberMe] = useState(false);
|
|
23
|
+
// Defaults per variant
|
|
24
|
+
const resolvedTitle = title ?? (variant === "work-email" ? "Sign in with your work email" : "Log In");
|
|
25
|
+
const resolvedSubtitle = subtitle ??
|
|
26
|
+
(variant === "work-email"
|
|
27
|
+
? "Use your work email to sign in to your team workspace"
|
|
28
|
+
: "Enter your credentials to access your account");
|
|
29
|
+
const resolvedSubmitLabel = submitLabel ?? (variant === "work-email" ? "Sign in" : "Log into Account");
|
|
30
|
+
const resolvedSignUpPrompt = signUpPrompt ?? (variant === "work-email" ? "Don't have an account?" : "Are you new here?");
|
|
31
|
+
const resolvedSignUpLabel = signUpLabel ?? (variant === "work-email" ? "Sign up" : "Create Account");
|
|
32
|
+
const resolvedProviders = socialProviders ?? [
|
|
33
|
+
{ name: "Google", icon: _jsx(GoogleIcon, {}) },
|
|
34
|
+
{ name: "Twitter", icon: _jsx(TwitterIcon, {}) },
|
|
35
|
+
];
|
|
36
|
+
const handleSubmit = (e) => {
|
|
37
|
+
e.preventDefault();
|
|
38
|
+
// Guard duplicate submission: `disabled` does not stop an implicit
|
|
39
|
+
// Enter-key submit in every browser, and the form may still be reachable
|
|
40
|
+
// while a request is in flight.
|
|
41
|
+
if (pending)
|
|
42
|
+
return;
|
|
43
|
+
onSubmit?.({ email, password, rememberMe });
|
|
44
|
+
};
|
|
45
|
+
const isWorkEmail = variant === "work-email";
|
|
46
|
+
const isCard = variant === "card";
|
|
47
|
+
// Social providers start a competing authentication route, so they follow the
|
|
48
|
+
// pending contract. Provider artwork stays literal brand colour; only the
|
|
49
|
+
// surrounding interface chrome is themeable.
|
|
50
|
+
const providerButtonClass = "flex items-center justify-center gap-4 w-full rounded-md border-[1.5px] border-surface-border-strong bg-surface p-4 text-base font-semibold text-grey-700 hover:bg-grey-50 dark:hover:bg-grey-100 transition-colors cursor-pointer disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-action-primary-text";
|
|
51
|
+
const socialSection = resolvedProviders.length > 0 && (_jsx("div", { className: "flex flex-col gap-3", children: resolvedProviders.map((provider) => (_jsxs("button", { type: "button", onClick: provider.onClick, disabled: pending, className: providerButtonClass, children: [_jsx("span", { className: "shrink-0 size-5", children: provider.icon }), "Continue with ", provider.name] }, provider.name))) }));
|
|
52
|
+
// Password recovery is independent of the remember-me option so every variant
|
|
53
|
+
// that supplies a handler can offer it.
|
|
54
|
+
const forgotPasswordAction = onForgotPassword && (_jsx("button", { type: "button", onClick: onForgotPassword, disabled: pending, className: "rounded text-sm font-medium text-action-primary-text cursor-pointer hover:underline underline-offset-2 disabled:cursor-not-allowed disabled:opacity-50 disabled:no-underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-action-primary-text", children: "Forgot Password?" }));
|
|
55
|
+
const showRememberMeRow = showRememberMe && !isWorkEmail;
|
|
56
|
+
const formContent = (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-col items-center gap-2 text-center", children: [_jsx("h2", { className: "text-h4 font-semibold text-grey-900", children: resolvedTitle }), _jsx("p", { className: "text-base text-grey-500", children: resolvedSubtitle })] }), isWorkEmail && socialSection && (_jsxs("div", { className: "mt-10 flex w-full flex-col gap-4", children: [_jsxs("button", { type: "button", onClick: resolvedProviders[0]?.onClick, disabled: pending, className: providerButtonClass, children: [_jsx("span", { className: "shrink-0 size-5", children: resolvedProviders[0]?.icon }), `Continue with ${resolvedProviders[0]?.name ?? "Google"}`] }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "h-px flex-1 bg-surface-border" }), _jsx("span", { className: "text-sm text-grey-500", children: "OR" }), _jsx("div", { className: "h-px flex-1 bg-surface-border" })] })] })), _jsxs("form", { onSubmit: handleSubmit, className: cn("flex flex-col", isWorkEmail ? "gap-6" : "gap-8", !isWorkEmail && "mt-10"), children: [_jsxs("div", { className: "flex flex-col gap-6", children: [_jsxs("div", { className: "flex flex-col gap-6", children: [_jsx(Input, { label: isWorkEmail ? "Email Address" : "EMAIL ADDRESS", placeholder: isWorkEmail ? "" : "Enter Email", size: "lg", type: "email", autoComplete: "email", required: true, disabled: pending, value: email, onChange: (e) => setEmail(e.target.value), trailingIcon: "mail" }), _jsx(Input, { label: "PASSWORD", placeholder: "Enter Password", type: showPassword ? "text" : "password", size: "lg", autoComplete: "current-password", required: true, disabled: pending, value: password, onChange: (e) => setPassword(e.target.value), trailingAction: _jsx("button", { type: "button", onClick: () => setShowPassword(!showPassword), "aria-label": showPassword ? "Hide password" : "Show password", "aria-pressed": showPassword, className: "flex size-6 items-center justify-center rounded text-grey-500 hover:text-grey-600 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-400", children: _jsx(Icon, { name: showPassword ? "eye" : "eye-slash", size: "sm" }) }) })] }), (showRememberMeRow || forgotPasswordAction) && (_jsxs("div", { className: cn("flex items-center gap-4", showRememberMeRow ? "justify-between" : "justify-end"), children: [showRememberMeRow && (_jsx(Checkbox, { label: rememberMeLabel, checked: rememberMe, disabled: pending, onChange: () => setRememberMe(!rememberMe), wrapperClassName: cn(pending && "cursor-not-allowed opacity-50") })), forgotPasswordAction] }))] }), error && (_jsx("p", { role: "alert", className: "text-sm text-feedback-error leading-[1.45]", children: error })), _jsx(Button, { type: "submit", variant: "primary", size: "lg", className: "w-full", disabled: pending, "aria-busy": pending || undefined, children: pending ? pendingLabel : resolvedSubmitLabel })] }), !isWorkEmail && socialSection && (_jsxs(_Fragment, { children: [_jsx(Divider, { variant: "with-label", label: "Or" }), socialSection] })), _jsxs("div", { className: "flex items-center justify-center gap-1", children: [_jsx("span", { className: "text-sm text-grey-500", children: resolvedSignUpPrompt }), _jsx("button", { type: "button", onClick: onSignUp, disabled: pending, className: "rounded text-sm font-medium text-action-primary-text cursor-pointer hover:underline underline-offset-2 disabled:cursor-not-allowed disabled:opacity-50 disabled:no-underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-action-primary-text", children: resolvedSignUpLabel })] })] }));
|
|
57
|
+
// Card variant wraps in a bordered card
|
|
58
|
+
if (isCard) {
|
|
59
|
+
return (_jsx("div", { className: cn("bg-surface border border-surface-border-strong rounded-10 px-7 py-8 w-full max-w-[432px]", className), children: _jsx("div", { className: "flex flex-col gap-8", children: formContent }) }));
|
|
60
|
+
}
|
|
61
|
+
// Standard / Work-email: no card wrapper
|
|
62
|
+
return (_jsx("div", { className: cn("flex flex-col items-center justify-center gap-6 w-full max-w-[400px] px-4 sm:px-0", className), children: formContent }));
|
|
63
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NotificationsBlock = NotificationsBlock;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const cn_1 = require("../utils/cn.cjs");
|
|
7
|
+
const ActivityItem_1 = require("../components/ActivityFeed/ActivityItem.cjs");
|
|
8
|
+
const ActivityContent_1 = require("../components/ActivityFeed/ActivityContent.cjs");
|
|
9
|
+
const Badge_1 = require("../components/Badge/index.cjs");
|
|
10
|
+
// ─── Component ───────────────────────────────────────────────────────
|
|
11
|
+
function NotificationsBlock({ title = "Notifications", headingLevel = 3, unreadCount, items, className, }) {
|
|
12
|
+
const headingId = (0, react_1.useId)();
|
|
13
|
+
const Heading = `h${headingLevel}`;
|
|
14
|
+
return ((0, jsx_runtime_1.jsxs)("section", { "aria-labelledby": headingId, className: (0, cn_1.cn)("bg-white dark:bg-grey-50 rounded-xl shadow-[0px_3px_2px_-2px_rgba(0,0,0,0.06),0px_5px_3px_-2px_rgba(0,0,0,0.02)] pt-4 pb-8", className), children: [(0, jsx_runtime_1.jsxs)("div", { className: "px-6 py-1.5 flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(Heading, { id: headingId, className: "flex-1 text-lg font-semibold text-grey-700", children: title }), unreadCount != null && unreadCount > 0 && ((0, jsx_runtime_1.jsxs)(Badge_1.Badge, { color: "success", type: "accent", size: "sm", children: [unreadCount, " unread"] }))] }), (0, jsx_runtime_1.jsx)("ul", { role: "list", className: "flex flex-col gap-4 px-6 mt-6 list-none", children: items.map((item) => {
|
|
15
|
+
return ((0, jsx_runtime_1.jsx)("li", { className: "min-w-0", children: (0, jsx_runtime_1.jsxs)(ActivityItem_1.ActivityItem, { avatar: item.avatar, text: item.text, date: item.date, time: item.time, unread: item.unread, link: item.link, badge: item.badge, children: [item.content?.type === "file" && ((0, jsx_runtime_1.jsx)(ActivityContent_1.ActivityContent, { variant: "file", contentStyle: "container", title: item.content.title, size: item.content.size, fileType: item.content.fileType, date: item.content.date })), item.content?.type === "comment" && ((0, jsx_runtime_1.jsx)(ActivityContent_1.ActivityContent, { variant: "comment", contentStyle: "container", avatar: item.content.avatar, author: item.content.author, timestamp: item.content.timestamp, comment: item.content.comment, reactions: item.content.reactions, replies: item.content.replies })), item.content?.type === "cta" && ((0, jsx_runtime_1.jsx)(ActivityContent_1.ActivityContent, { variant: "cta", primaryAction: item.content.primaryAction, secondaryAction: item.content.secondaryAction }))] }) }, item.id));
|
|
16
|
+
}) })] }));
|
|
17
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useId } from "react";
|
|
3
|
+
import { cn } from "../utils/cn.js";
|
|
4
|
+
import { ActivityItem } from "../components/ActivityFeed/ActivityItem.js";
|
|
5
|
+
import { ActivityContent } from "../components/ActivityFeed/ActivityContent.js";
|
|
6
|
+
import { Badge } from "../components/Badge/index.js";
|
|
7
|
+
// ─── Component ───────────────────────────────────────────────────────
|
|
8
|
+
export function NotificationsBlock({ title = "Notifications", headingLevel = 3, unreadCount, items, className, }) {
|
|
9
|
+
const headingId = useId();
|
|
10
|
+
const Heading = `h${headingLevel}`;
|
|
11
|
+
return (_jsxs("section", { "aria-labelledby": headingId, className: cn("bg-white dark:bg-grey-50 rounded-xl shadow-[0px_3px_2px_-2px_rgba(0,0,0,0.06),0px_5px_3px_-2px_rgba(0,0,0,0.02)] pt-4 pb-8", className), children: [_jsxs("div", { className: "px-6 py-1.5 flex items-center gap-2", children: [_jsx(Heading, { id: headingId, className: "flex-1 text-lg font-semibold text-grey-700", children: title }), unreadCount != null && unreadCount > 0 && (_jsxs(Badge, { color: "success", type: "accent", size: "sm", children: [unreadCount, " unread"] }))] }), _jsx("ul", { role: "list", className: "flex flex-col gap-4 px-6 mt-6 list-none", children: items.map((item) => {
|
|
12
|
+
return (_jsx("li", { className: "min-w-0", children: _jsxs(ActivityItem, { avatar: item.avatar, text: item.text, date: item.date, time: item.time, unread: item.unread, link: item.link, badge: item.badge, children: [item.content?.type === "file" && (_jsx(ActivityContent, { variant: "file", contentStyle: "container", title: item.content.title, size: item.content.size, fileType: item.content.fileType, date: item.content.date })), item.content?.type === "comment" && (_jsx(ActivityContent, { variant: "comment", contentStyle: "container", avatar: item.content.avatar, author: item.content.author, timestamp: item.content.timestamp, comment: item.content.comment, reactions: item.content.reactions, replies: item.content.replies })), item.content?.type === "cta" && (_jsx(ActivityContent, { variant: "cta", primaryAction: item.content.primaryAction, secondaryAction: item.content.secondaryAction }))] }) }, item.id));
|
|
13
|
+
}) })] }));
|
|
14
|
+
}
|