@raydenui/ui 0.9.7 → 0.10.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 +124 -49
- 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,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CheckoutReviewBlock = CheckoutReviewBlock;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const Button_1 = require("../components/Button/index.cjs");
|
|
6
|
+
const commerce_1 = require("./commerce.cjs");
|
|
7
|
+
function CheckoutReviewBlock({ title = "Review your order", description = "Check the details before placing your order.", items, deliveryAddress, deliveryMethod, paymentSummary, onEditDelivery, onEditPayment, onEditCart, onConfirm, confirmLabel = "Place order", pending = false, errorMessage, confirmation, terms, totalsNote, shipping, tax, discount, currency, locale, ...frame }) {
|
|
8
|
+
const canConfirm = items.length > 0 &&
|
|
9
|
+
deliveryAddress.some((line) => line.trim()) &&
|
|
10
|
+
deliveryMethod.trim() &&
|
|
11
|
+
paymentSummary.trim() &&
|
|
12
|
+
items.every((item) => Number.isInteger(item.quantity) &&
|
|
13
|
+
item.quantity > 0 &&
|
|
14
|
+
item.quantity <= (item.stock ?? Infinity));
|
|
15
|
+
return ((0, jsx_runtime_1.jsx)(commerce_1.CommerceFrame, { ...frame, title: confirmation?.title ?? title, description: confirmation ? confirmation.description : description, busy: pending, children: confirmation ? ((0, jsx_runtime_1.jsxs)("div", { role: "status", className: "rounded-2xl bg-surface-muted p-6", children: [(0, jsx_runtime_1.jsx)("p", { className: "font-medium", children: confirmation.title }), confirmation.reference && ((0, jsx_runtime_1.jsxs)("p", { className: "mt-2 text-sm text-grey-600", children: ["Order reference: ", confirmation.reference] }))] })) : ((0, jsx_runtime_1.jsxs)("div", { className: "grid items-start gap-8 @min-[760px]:grid-cols-[minmax(0,1.3fr)_minmax(0,1fr)] @min-[960px]:gap-14", children: [(0, jsx_runtime_1.jsxs)("div", { className: "min-w-0 space-y-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "border-b border-surface-border pb-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-lg font-semibold tracking-tight", children: "Delivery details" }), onEditDelivery && ((0, jsx_runtime_1.jsx)("button", { type: "button", disabled: pending, className: `${commerce_1.commerceControl} border-transparent bg-transparent px-2 text-sm underline underline-offset-4 hover:border-transparent`, onClick: onEditDelivery, children: "Edit delivery" }))] }), (0, jsx_runtime_1.jsx)("address", { className: "mt-3 text-sm leading-relaxed not-italic text-grey-600", children: deliveryAddress.map((line, i) => ((0, jsx_runtime_1.jsx)("span", { className: "block", children: line }, i))) }), (0, jsx_runtime_1.jsx)("p", { className: "mt-3 text-sm", children: deliveryMethod })] }), (0, jsx_runtime_1.jsxs)("div", { className: "border-b border-surface-border pb-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-lg font-semibold tracking-tight", children: "Payment method" }), onEditPayment && ((0, jsx_runtime_1.jsx)("button", { type: "button", disabled: pending, className: `${commerce_1.commerceControl} border-transparent bg-transparent px-2 text-sm underline underline-offset-4 hover:border-transparent`, onClick: onEditPayment, children: "Edit payment" }))] }), (0, jsx_runtime_1.jsx)("p", { className: "mt-3 text-sm text-grey-600", children: paymentSummary })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "mb-3 flex flex-wrap items-center justify-between gap-3", children: [(0, jsx_runtime_1.jsx)("p", { className: "font-semibold", children: "Items in your order" }), onEditCart && ((0, jsx_runtime_1.jsx)("button", { type: "button", disabled: pending, className: `${commerce_1.commerceControl} border-transparent bg-transparent px-2 text-sm underline underline-offset-4 hover:border-transparent`, onClick: onEditCart, children: "Edit bag" }))] }), (0, jsx_runtime_1.jsx)("ul", { className: "divide-y divide-surface-border", children: items.map((item) => ((0, jsx_runtime_1.jsxs)("li", { className: "grid grid-cols-[48px_minmax(0,1fr)_auto] items-center gap-3 py-4 text-sm", children: [(0, jsx_runtime_1.jsx)(commerce_1.CommercePhoto, { image: item.image, className: "rounded" }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { className: "font-medium", children: item.name }), (0, jsx_runtime_1.jsxs)("p", { className: "mt-1 text-grey-600", children: [item.variant ? `${item.variant} · ` : "", "Quantity: ", item.quantity] })] }), (0, jsx_runtime_1.jsx)("p", { className: "text-right tabular-nums", children: (0, commerce_1.formatCommerceMoney)(item.price * item.quantity, currency, locale) })] }, item.id))) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "rounded-xl border border-surface-border bg-surface-muted p-5 @min-[440px]:p-6", children: [(0, jsx_runtime_1.jsx)("p", { className: "mb-6 text-lg font-semibold tracking-tight", children: "Order total" }), (0, jsx_runtime_1.jsx)(commerce_1.CommerceTotals, { items: items, shipping: shipping, tax: tax, discount: discount, currency: currency, locale: locale }), totalsNote && (0, jsx_runtime_1.jsx)("p", { className: "mt-4 text-sm text-grey-600", children: totalsNote }), terms && (0, jsx_runtime_1.jsx)("div", { className: "mt-5 text-sm leading-relaxed text-grey-600", children: terms }), errorMessage && ((0, jsx_runtime_1.jsx)("p", { role: "alert", className: "mt-4 text-sm text-error-700", children: errorMessage })), !canConfirm && ((0, jsx_runtime_1.jsx)("p", { role: "status", className: "mt-4 text-sm text-error-700", children: "Add available items and complete the delivery and payment details to continue." })), onConfirm && ((0, jsx_runtime_1.jsx)(Button_1.Button, { disabled: pending || !canConfirm, className: "mt-6 h-auto min-h-12 w-full whitespace-normal", onClick: onConfirm, children: pending ? "Placing order…" : confirmLabel }))] })] })) }));
|
|
16
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button } from "../components/Button/index.js";
|
|
3
|
+
import { CommerceFrame, CommerceTotals, CommercePhoto, commerceControl, formatCommerceMoney, } from "./commerce.js";
|
|
4
|
+
export function CheckoutReviewBlock({ title = "Review your order", description = "Check the details before placing your order.", items, deliveryAddress, deliveryMethod, paymentSummary, onEditDelivery, onEditPayment, onEditCart, onConfirm, confirmLabel = "Place order", pending = false, errorMessage, confirmation, terms, totalsNote, shipping, tax, discount, currency, locale, ...frame }) {
|
|
5
|
+
const canConfirm = items.length > 0 &&
|
|
6
|
+
deliveryAddress.some((line) => line.trim()) &&
|
|
7
|
+
deliveryMethod.trim() &&
|
|
8
|
+
paymentSummary.trim() &&
|
|
9
|
+
items.every((item) => Number.isInteger(item.quantity) &&
|
|
10
|
+
item.quantity > 0 &&
|
|
11
|
+
item.quantity <= (item.stock ?? Infinity));
|
|
12
|
+
return (_jsx(CommerceFrame, { ...frame, title: confirmation?.title ?? title, description: confirmation ? confirmation.description : description, busy: pending, children: confirmation ? (_jsxs("div", { role: "status", className: "rounded-2xl bg-surface-muted p-6", children: [_jsx("p", { className: "font-medium", children: confirmation.title }), confirmation.reference && (_jsxs("p", { className: "mt-2 text-sm text-grey-600", children: ["Order reference: ", confirmation.reference] }))] })) : (_jsxs("div", { className: "grid items-start gap-8 @min-[760px]:grid-cols-[minmax(0,1.3fr)_minmax(0,1fr)] @min-[960px]:gap-14", children: [_jsxs("div", { className: "min-w-0 space-y-6", children: [_jsxs("div", { className: "border-b border-surface-border pb-6", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx("p", { className: "text-lg font-semibold tracking-tight", children: "Delivery details" }), onEditDelivery && (_jsx("button", { type: "button", disabled: pending, className: `${commerceControl} border-transparent bg-transparent px-2 text-sm underline underline-offset-4 hover:border-transparent`, onClick: onEditDelivery, children: "Edit delivery" }))] }), _jsx("address", { className: "mt-3 text-sm leading-relaxed not-italic text-grey-600", children: deliveryAddress.map((line, i) => (_jsx("span", { className: "block", children: line }, i))) }), _jsx("p", { className: "mt-3 text-sm", children: deliveryMethod })] }), _jsxs("div", { className: "border-b border-surface-border pb-6", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx("p", { className: "text-lg font-semibold tracking-tight", children: "Payment method" }), onEditPayment && (_jsx("button", { type: "button", disabled: pending, className: `${commerceControl} border-transparent bg-transparent px-2 text-sm underline underline-offset-4 hover:border-transparent`, onClick: onEditPayment, children: "Edit payment" }))] }), _jsx("p", { className: "mt-3 text-sm text-grey-600", children: paymentSummary })] }), _jsxs("div", { children: [_jsxs("div", { className: "mb-3 flex flex-wrap items-center justify-between gap-3", children: [_jsx("p", { className: "font-semibold", children: "Items in your order" }), onEditCart && (_jsx("button", { type: "button", disabled: pending, className: `${commerceControl} border-transparent bg-transparent px-2 text-sm underline underline-offset-4 hover:border-transparent`, onClick: onEditCart, children: "Edit bag" }))] }), _jsx("ul", { className: "divide-y divide-surface-border", children: items.map((item) => (_jsxs("li", { className: "grid grid-cols-[48px_minmax(0,1fr)_auto] items-center gap-3 py-4 text-sm", children: [_jsx(CommercePhoto, { image: item.image, className: "rounded" }), _jsxs("div", { children: [_jsx("p", { className: "font-medium", children: item.name }), _jsxs("p", { className: "mt-1 text-grey-600", children: [item.variant ? `${item.variant} · ` : "", "Quantity: ", item.quantity] })] }), _jsx("p", { className: "text-right tabular-nums", children: formatCommerceMoney(item.price * item.quantity, currency, locale) })] }, item.id))) })] })] }), _jsxs("div", { className: "rounded-xl border border-surface-border bg-surface-muted p-5 @min-[440px]:p-6", children: [_jsx("p", { className: "mb-6 text-lg font-semibold tracking-tight", children: "Order total" }), _jsx(CommerceTotals, { items: items, shipping: shipping, tax: tax, discount: discount, currency: currency, locale: locale }), totalsNote && _jsx("p", { className: "mt-4 text-sm text-grey-600", children: totalsNote }), terms && _jsx("div", { className: "mt-5 text-sm leading-relaxed text-grey-600", children: terms }), errorMessage && (_jsx("p", { role: "alert", className: "mt-4 text-sm text-error-700", children: errorMessage })), !canConfirm && (_jsx("p", { role: "status", className: "mt-4 text-sm text-error-700", children: "Add available items and complete the delivery and payment details to continue." })), onConfirm && (_jsx(Button, { disabled: pending || !canConfirm, className: "mt-6 h-auto min-h-12 w-full whitespace-normal", onClick: onConfirm, children: pending ? "Placing order…" : confirmLabel }))] })] })) }));
|
|
13
|
+
}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CommandPaletteBlock = CommandPaletteBlock;
|
|
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 Icon_1 = require("../components/Icon/index.cjs");
|
|
8
|
+
const Spinner_1 = require("../components/Spinner/index.cjs");
|
|
9
|
+
/* ─── Recipes ────────────────────────────────────────────────────────── */
|
|
10
|
+
const FOCUS_RING = "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-action-primary-text";
|
|
11
|
+
/**
|
|
12
|
+
* Only elements Tab can actually reach. A roving-tabindex option is an
|
|
13
|
+
* `a[href]` parked at `tabindex="-1"`: focusable in code, skipped by Tab. Left
|
|
14
|
+
* in this list it became the computed final stop and focus escaped the dialog.
|
|
15
|
+
*/
|
|
16
|
+
const FOCUSABLE = [
|
|
17
|
+
'a[href]:not([tabindex="-1"])',
|
|
18
|
+
'button:not([disabled]):not([tabindex="-1"])',
|
|
19
|
+
'input:not([disabled]):not([tabindex="-1"])',
|
|
20
|
+
'select:not([disabled]):not([tabindex="-1"])',
|
|
21
|
+
'textarea:not([disabled]):not([tabindex="-1"])',
|
|
22
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
23
|
+
].join(", ");
|
|
24
|
+
function itemMatches(item, needle) {
|
|
25
|
+
const haystack = [item.label, item.description ?? "", ...(item.keywords ?? [])]
|
|
26
|
+
.join(" ")
|
|
27
|
+
.toLocaleLowerCase();
|
|
28
|
+
return haystack.includes(needle);
|
|
29
|
+
}
|
|
30
|
+
/* ─── Component ──────────────────────────────────────────────────────── */
|
|
31
|
+
function CommandPaletteBlock({ items = [], groups = [], suggestions, suggestionsLabel = "Suggestions", showAllWhenEmpty = false, filterMode = "local", onQueryChange, onSelect, status = "idle", errorTitle = "Search is unavailable", errorDescription = "The search service did not respond. Nothing has been changed.", onRetry, loadingMessage = "Searching", dialogLabel = "Command palette", searchLabel = "Search destinations and actions", searchPlaceholder = "Search or jump to…", searchHint = "Use the up and down arrow keys to move through results, then Enter to open one.", promptTitle = "Type to search", promptDescription = "Start typing to find a page, a record, or an action.", noResultsTitle = (query) => `No results for “${query}”`, noResultsDescription = "Check the spelling, or try a shorter search term.", emptySourceTitle = "Nothing is available to search yet", emptySourceDescription = "This workspace has no destinations or actions configured.", resultCountLabel = (count) => (count === 1 ? "1 result" : `${count} results`), showTrigger = true, triggerLabel = "Search", triggerClassName, shortcut = null, defaultOpen = false, open: controlledOpen, onOpenChange, closeLabel = "Close", lockScroll = true, footer, className, }) {
|
|
32
|
+
const uid = (0, react_1.useId)();
|
|
33
|
+
const dialogId = `${uid}-dialog`;
|
|
34
|
+
const listId = `${uid}-list`;
|
|
35
|
+
const inputId = `${uid}-input`;
|
|
36
|
+
const hintId = `${uid}-hint`;
|
|
37
|
+
const [uncontrolledOpen, setUncontrolledOpen] = (0, react_1.useState)(defaultOpen);
|
|
38
|
+
const open = controlledOpen ?? uncontrolledOpen;
|
|
39
|
+
const [query, setQuery] = (0, react_1.useState)("");
|
|
40
|
+
const [activeIndex, setActiveIndex] = (0, react_1.useState)(0);
|
|
41
|
+
const triggerRef = (0, react_1.useRef)(null);
|
|
42
|
+
const dialogRef = (0, react_1.useRef)(null);
|
|
43
|
+
const inputRef = (0, react_1.useRef)(null);
|
|
44
|
+
const listRef = (0, react_1.useRef)(null);
|
|
45
|
+
/** Whatever had focus before the overlay opened, restored on close. */
|
|
46
|
+
const returnFocusRef = (0, react_1.useRef)(null);
|
|
47
|
+
const setOpen = (0, react_1.useCallback)((next) => {
|
|
48
|
+
if (controlledOpen === undefined)
|
|
49
|
+
setUncontrolledOpen(next);
|
|
50
|
+
onOpenChange?.(next);
|
|
51
|
+
}, [controlledOpen, onOpenChange]);
|
|
52
|
+
const close = (0, react_1.useCallback)(() => setOpen(false), [setOpen]);
|
|
53
|
+
/* ── Result set ──────────────────────────────────────────────────── */
|
|
54
|
+
const trimmed = query.trim();
|
|
55
|
+
const needle = trimmed.toLocaleLowerCase();
|
|
56
|
+
const results = (0, react_1.useMemo)(() => {
|
|
57
|
+
if (!trimmed) {
|
|
58
|
+
if (suggestions && suggestions.length > 0)
|
|
59
|
+
return suggestions;
|
|
60
|
+
return showAllWhenEmpty ? items : [];
|
|
61
|
+
}
|
|
62
|
+
if (filterMode === "external")
|
|
63
|
+
return items;
|
|
64
|
+
return items.filter((item) => itemMatches(item, needle));
|
|
65
|
+
}, [trimmed, needle, items, suggestions, showAllWhenEmpty, filterMode]);
|
|
66
|
+
const showingSuggestions = !trimmed && Boolean(suggestions && suggestions.length > 0);
|
|
67
|
+
const hasSource = items.length > 0 || (suggestions?.length ?? 0) > 0;
|
|
68
|
+
const promptState = !trimmed && results.length === 0 && hasSource;
|
|
69
|
+
const noResultsState = Boolean(trimmed) && results.length === 0 && status === "idle";
|
|
70
|
+
/** Grouped for display, ordered by `groups`, with anything ungrouped first. */
|
|
71
|
+
const sections = (0, react_1.useMemo)(() => {
|
|
72
|
+
if (showingSuggestions) {
|
|
73
|
+
return [{ id: "__suggestions", label: suggestionsLabel, items: results }];
|
|
74
|
+
}
|
|
75
|
+
const ungrouped = results.filter((item) => !item.groupId);
|
|
76
|
+
const known = groups
|
|
77
|
+
.map((group) => ({
|
|
78
|
+
id: group.id,
|
|
79
|
+
label: group.label,
|
|
80
|
+
items: results.filter((item) => item.groupId === group.id),
|
|
81
|
+
}))
|
|
82
|
+
.filter((section) => section.items.length > 0);
|
|
83
|
+
const knownIds = new Set(groups.map((group) => group.id));
|
|
84
|
+
const orphans = results.filter((item) => item.groupId && !knownIds.has(item.groupId));
|
|
85
|
+
const head = ungrouped.length > 0 || orphans.length > 0
|
|
86
|
+
? [
|
|
87
|
+
{
|
|
88
|
+
id: "__ungrouped",
|
|
89
|
+
label: undefined,
|
|
90
|
+
items: [...ungrouped, ...orphans],
|
|
91
|
+
},
|
|
92
|
+
]
|
|
93
|
+
: [];
|
|
94
|
+
return [...head, ...known];
|
|
95
|
+
}, [results, groups, showingSuggestions, suggestionsLabel]);
|
|
96
|
+
/** Flat order, so arrow keys cross group boundaries the way the eye does. */
|
|
97
|
+
const flatItems = (0, react_1.useMemo)(() => sections.flatMap((section) => section.items), [sections]);
|
|
98
|
+
(0, react_1.useEffect)(() => {
|
|
99
|
+
setActiveIndex(0);
|
|
100
|
+
}, [query, open]);
|
|
101
|
+
/* ── Open / close side effects ───────────────────────────────────── */
|
|
102
|
+
(0, react_1.useEffect)(() => {
|
|
103
|
+
if (!open)
|
|
104
|
+
return;
|
|
105
|
+
returnFocusRef.current = document.activeElement ?? null;
|
|
106
|
+
// Focused in the same commit that removes `hidden`, so the field has focus
|
|
107
|
+
// by the time the click that opened the dialog has settled.
|
|
108
|
+
inputRef.current?.focus();
|
|
109
|
+
}, [open]);
|
|
110
|
+
(0, react_1.useEffect)(() => {
|
|
111
|
+
if (open)
|
|
112
|
+
return;
|
|
113
|
+
setQuery("");
|
|
114
|
+
}, [open]);
|
|
115
|
+
/**
|
|
116
|
+
* Focus goes back to whatever opened the palette, which is the trigger when
|
|
117
|
+
* the block renders its own. A dialog that drops focus on the document body
|
|
118
|
+
* strands a keyboard user at the top of the page.
|
|
119
|
+
*/
|
|
120
|
+
const wasOpen = (0, react_1.useRef)(open);
|
|
121
|
+
(0, react_1.useEffect)(() => {
|
|
122
|
+
if (wasOpen.current && !open) {
|
|
123
|
+
const target = triggerRef.current ?? returnFocusRef.current;
|
|
124
|
+
target?.focus();
|
|
125
|
+
}
|
|
126
|
+
wasOpen.current = open;
|
|
127
|
+
}, [open]);
|
|
128
|
+
(0, react_1.useEffect)(() => {
|
|
129
|
+
if (!open || !lockScroll || typeof document === "undefined")
|
|
130
|
+
return;
|
|
131
|
+
const previous = document.body.style.overflow;
|
|
132
|
+
document.body.style.overflow = "hidden";
|
|
133
|
+
return () => {
|
|
134
|
+
document.body.style.overflow = previous;
|
|
135
|
+
};
|
|
136
|
+
}, [open, lockScroll]);
|
|
137
|
+
(0, react_1.useEffect)(() => {
|
|
138
|
+
if (!shortcut || typeof document === "undefined")
|
|
139
|
+
return;
|
|
140
|
+
const wanted = shortcut.key.toLowerCase();
|
|
141
|
+
const modifier = shortcut.modifier ?? "mod";
|
|
142
|
+
function handle(event) {
|
|
143
|
+
if (event.defaultPrevented || event.isComposing || event.repeat)
|
|
144
|
+
return;
|
|
145
|
+
if (event.key.toLowerCase() !== wanted)
|
|
146
|
+
return;
|
|
147
|
+
const target = event.target;
|
|
148
|
+
// Single-letter shortcuts must never consume text entry, including our search field.
|
|
149
|
+
if (modifier === "none" &&
|
|
150
|
+
(event.altKey ||
|
|
151
|
+
event.shiftKey ||
|
|
152
|
+
(target instanceof HTMLElement &&
|
|
153
|
+
(target.isContentEditable ||
|
|
154
|
+
target.closest("input, textarea, select, [role='textbox']")))))
|
|
155
|
+
return;
|
|
156
|
+
const mod = event.metaKey || event.ctrlKey;
|
|
157
|
+
if (modifier === "mod" && !mod)
|
|
158
|
+
return;
|
|
159
|
+
if (modifier === "none" && mod)
|
|
160
|
+
return;
|
|
161
|
+
event.preventDefault();
|
|
162
|
+
setOpen(true);
|
|
163
|
+
}
|
|
164
|
+
document.addEventListener("keydown", handle);
|
|
165
|
+
return () => document.removeEventListener("keydown", handle);
|
|
166
|
+
}, [shortcut, setOpen]);
|
|
167
|
+
/* ── Roving focus ────────────────────────────────────────────────── */
|
|
168
|
+
function optionNodes() {
|
|
169
|
+
if (!listRef.current)
|
|
170
|
+
return [];
|
|
171
|
+
return Array.from(listRef.current.querySelectorAll("[data-option]"));
|
|
172
|
+
}
|
|
173
|
+
function focusOptionAt(index) {
|
|
174
|
+
const nodes = optionNodes();
|
|
175
|
+
if (nodes.length === 0)
|
|
176
|
+
return;
|
|
177
|
+
const wrapped = ((index % nodes.length) + nodes.length) % nodes.length;
|
|
178
|
+
setActiveIndex(wrapped);
|
|
179
|
+
nodes[wrapped]?.focus();
|
|
180
|
+
}
|
|
181
|
+
function activateAt(index) {
|
|
182
|
+
const nodes = optionNodes();
|
|
183
|
+
nodes[index]?.click();
|
|
184
|
+
}
|
|
185
|
+
function handleInputKeyDown(event) {
|
|
186
|
+
if (event.key === "ArrowDown") {
|
|
187
|
+
event.preventDefault();
|
|
188
|
+
focusOptionAt(0);
|
|
189
|
+
}
|
|
190
|
+
else if (event.key === "ArrowUp") {
|
|
191
|
+
event.preventDefault();
|
|
192
|
+
focusOptionAt(-1);
|
|
193
|
+
}
|
|
194
|
+
else if (event.key === "Enter" && flatItems.length > 0) {
|
|
195
|
+
event.preventDefault();
|
|
196
|
+
activateAt(activeIndex);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function handleOptionKeyDown(event, index) {
|
|
200
|
+
switch (event.key) {
|
|
201
|
+
case "ArrowDown":
|
|
202
|
+
event.preventDefault();
|
|
203
|
+
focusOptionAt(index + 1);
|
|
204
|
+
break;
|
|
205
|
+
case "ArrowUp":
|
|
206
|
+
event.preventDefault();
|
|
207
|
+
focusOptionAt(index - 1);
|
|
208
|
+
break;
|
|
209
|
+
case "Home":
|
|
210
|
+
event.preventDefault();
|
|
211
|
+
focusOptionAt(0);
|
|
212
|
+
break;
|
|
213
|
+
case "End":
|
|
214
|
+
event.preventDefault();
|
|
215
|
+
focusOptionAt(-1);
|
|
216
|
+
break;
|
|
217
|
+
default:
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/** Tab stays inside the overlay; Escape leaves it. */
|
|
222
|
+
function handleDialogKeyDown(event) {
|
|
223
|
+
if (event.key === "Escape") {
|
|
224
|
+
event.preventDefault();
|
|
225
|
+
close();
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
if (event.key !== "Tab" || !dialogRef.current)
|
|
229
|
+
return;
|
|
230
|
+
const nodes = Array.from(dialogRef.current.querySelectorAll(FOCUSABLE)).filter((node) => node.offsetParent !== null || node === document.activeElement);
|
|
231
|
+
if (nodes.length === 0)
|
|
232
|
+
return;
|
|
233
|
+
const first = nodes[0];
|
|
234
|
+
const last = nodes[nodes.length - 1];
|
|
235
|
+
const active = document.activeElement;
|
|
236
|
+
if (event.shiftKey && (active === first || !dialogRef.current.contains(active))) {
|
|
237
|
+
event.preventDefault();
|
|
238
|
+
last.focus();
|
|
239
|
+
}
|
|
240
|
+
else if (!event.shiftKey && active === last) {
|
|
241
|
+
event.preventDefault();
|
|
242
|
+
first.focus();
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
/* ── Option ──────────────────────────────────────────────────────── */
|
|
246
|
+
function renderOption(item, index) {
|
|
247
|
+
const unavailable = "unavailableReason" in item ? item.unavailableReason : undefined;
|
|
248
|
+
const reasonId = `${uid}-${item.id}-reason`;
|
|
249
|
+
const isActive = index === activeIndex;
|
|
250
|
+
const body = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [item.icon && ((0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: item.icon, size: "md", className: (0, cn_1.cn)("mt-0.5 shrink-0", unavailable ? "text-grey-400" : "text-grey-500") })), (0, jsx_runtime_1.jsxs)("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5 text-left", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-body-sm font-medium break-words", children: item.label }), item.description && ((0, jsx_runtime_1.jsx)("span", { className: "text-body-xs break-words text-grey-500", children: item.description })), unavailable && ((0, jsx_runtime_1.jsx)("span", { id: reasonId, className: "text-body-xs break-words text-grey-500", children: unavailable }))] }), item.shortcut && ((0, jsx_runtime_1.jsx)("span", { "aria-hidden": "true", className: "ml-auto shrink-0 rounded border border-surface-border px-1.5 py-0.5 text-body-xs font-medium text-grey-500", children: item.shortcut }))] }));
|
|
251
|
+
const classes = (0, cn_1.cn)("flex w-full min-w-0 items-start gap-3 rounded-lg px-3 py-2 transition-colors", FOCUS_RING, unavailable
|
|
252
|
+
? "cursor-not-allowed text-grey-500"
|
|
253
|
+
: "cursor-pointer text-grey-900 hover:bg-surface-muted");
|
|
254
|
+
const shared = {
|
|
255
|
+
"data-option": "true",
|
|
256
|
+
role: "option",
|
|
257
|
+
"aria-selected": isActive,
|
|
258
|
+
tabIndex: isActive ? 0 : -1,
|
|
259
|
+
className: classes,
|
|
260
|
+
};
|
|
261
|
+
if (unavailable) {
|
|
262
|
+
return ((0, jsx_runtime_1.jsx)("div", { ...shared, "aria-disabled": "true", "aria-describedby": reasonId, onKeyDown: (event) => handleOptionKeyDown(event, index), onFocus: () => setActiveIndex(index), children: body }, item.id));
|
|
263
|
+
}
|
|
264
|
+
if (item.href) {
|
|
265
|
+
// Destinations stay anchors: Enter activates them natively, middle-click
|
|
266
|
+
// opens a new tab, and the href is never rebuilt into a dead button.
|
|
267
|
+
return ((0, jsx_runtime_1.jsx)("a", { ...shared, href: item.href, ...(item.external ? { target: "_blank", rel: "noreferrer" } : {}), onClick: () => {
|
|
268
|
+
item.onSelect?.();
|
|
269
|
+
onSelect?.(item);
|
|
270
|
+
close();
|
|
271
|
+
}, onKeyDown: (event) => handleOptionKeyDown(event, index), onFocus: () => setActiveIndex(index), children: body }, item.id));
|
|
272
|
+
}
|
|
273
|
+
return ((0, jsx_runtime_1.jsx)("div", { ...shared, onClick: () => {
|
|
274
|
+
item.onSelect?.();
|
|
275
|
+
onSelect?.(item);
|
|
276
|
+
close();
|
|
277
|
+
}, onKeyDown: (event) => {
|
|
278
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
279
|
+
event.preventDefault();
|
|
280
|
+
item.onSelect?.();
|
|
281
|
+
onSelect?.(item);
|
|
282
|
+
close();
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
handleOptionKeyDown(event, index);
|
|
286
|
+
}, onFocus: () => setActiveIndex(index), children: body }, item.id));
|
|
287
|
+
}
|
|
288
|
+
/* ── Body ────────────────────────────────────────────────────────── */
|
|
289
|
+
function renderBody() {
|
|
290
|
+
if (status === "loading") {
|
|
291
|
+
return ((0, jsx_runtime_1.jsxs)("p", { role: "status", className: "flex items-center gap-2 px-4 py-10 text-body-sm text-grey-500", children: [(0, jsx_runtime_1.jsx)(Spinner_1.Spinner, { size: "sm" }), (0, jsx_runtime_1.jsx)("span", { children: loadingMessage })] }));
|
|
292
|
+
}
|
|
293
|
+
if (status === "error") {
|
|
294
|
+
return ((0, jsx_runtime_1.jsxs)("div", { role: "alert", className: "m-3 flex flex-col gap-2 rounded-lg border border-error-200 bg-error-50 px-4 py-3 text-error-700", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-body-sm font-semibold break-words", children: errorTitle }), (0, jsx_runtime_1.jsx)("p", { className: "text-body-sm break-words", children: errorDescription }), onRetry && ((0, jsx_runtime_1.jsxs)("button", { type: "button", onClick: onRetry, className: (0, cn_1.cn)("inline-flex min-h-10 w-fit cursor-pointer items-center gap-2 rounded-lg border-[1.5px] border-current px-4 py-2 text-body-sm font-semibold", FOCUS_RING), children: [(0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: "refresh", size: "sm" }), "Try again"] }))] }));
|
|
295
|
+
}
|
|
296
|
+
if (!hasSource) {
|
|
297
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-1 px-4 py-10 text-center", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-body-sm font-semibold break-words text-grey-900", children: emptySourceTitle }), (0, jsx_runtime_1.jsx)("p", { className: "text-body-sm break-words text-grey-500", children: emptySourceDescription })] }));
|
|
298
|
+
}
|
|
299
|
+
if (promptState) {
|
|
300
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-1 px-4 py-10 text-center", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-body-sm font-semibold break-words text-grey-900", children: promptTitle }), (0, jsx_runtime_1.jsx)("p", { className: "text-body-sm break-words text-grey-500", children: promptDescription })] }));
|
|
301
|
+
}
|
|
302
|
+
if (noResultsState) {
|
|
303
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-1 px-4 py-10 text-center", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-body-sm font-semibold break-words text-grey-900", children: noResultsTitle(trimmed) }), (0, jsx_runtime_1.jsx)("p", { className: "text-body-sm break-words text-grey-500", children: noResultsDescription })] }));
|
|
304
|
+
}
|
|
305
|
+
let cursor = -1;
|
|
306
|
+
return ((0, jsx_runtime_1.jsx)("div", { ref: listRef, role: "listbox", "aria-label": dialogLabel, className: "flex flex-col gap-3 p-2", children: sections.map((section) => {
|
|
307
|
+
const sectionHeadingId = `${uid}-${section.id}-label`;
|
|
308
|
+
return ((0, jsx_runtime_1.jsxs)("div", { role: "group", ...(section.label ? { "aria-labelledby": sectionHeadingId } : {}), className: "flex flex-col gap-0.5", children: [section.label && ((0, jsx_runtime_1.jsx)("p", { id: sectionHeadingId, className: "px-3 pt-1 pb-1 text-caption-sm font-semibold break-words text-grey-500 uppercase", children: section.label })), section.items.map((item) => {
|
|
309
|
+
cursor += 1;
|
|
310
|
+
return renderOption(item, cursor);
|
|
311
|
+
})] }, section.id));
|
|
312
|
+
}) }));
|
|
313
|
+
}
|
|
314
|
+
const countText = status === "idle" && hasSource && !promptState ? resultCountLabel(flatItems.length) : "";
|
|
315
|
+
/* ── Render ──────────────────────────────────────────────────────── */
|
|
316
|
+
return (
|
|
317
|
+
// Not an `@container`: the trigger is a flex item in the shell's top bar,
|
|
318
|
+
// and inline-size containment would stop it sizing from its own contents.
|
|
319
|
+
// The overlay is viewport-anchored, so nothing here needs a container query.
|
|
320
|
+
(0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("relative w-full min-w-0", className), children: [showTrigger && ((0, jsx_runtime_1.jsxs)("button", { ref: triggerRef, type: "button", "aria-haspopup": "dialog", "aria-expanded": open, "aria-controls": dialogId, onClick: () => setOpen(true), className: (0, cn_1.cn)("flex min-h-11 w-full min-w-0 cursor-pointer items-center gap-2 rounded-lg border border-surface-border bg-surface px-3 py-2 text-left text-body-sm text-grey-500 transition-colors hover:bg-surface-muted", FOCUS_RING, triggerClassName), children: [(0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: "search", size: "sm", className: "shrink-0" }), (0, jsx_runtime_1.jsx)("span", { className: "min-w-0 truncate", children: triggerLabel }), shortcut?.hint && ((0, jsx_runtime_1.jsx)("span", { "aria-hidden": "true", className: "ml-auto hidden shrink-0 rounded border border-surface-border px-1.5 py-0.5 text-body-xs font-medium sm:inline", children: shortcut.hint }))] })), (0, jsx_runtime_1.jsxs)("div", { id: dialogId, className: (0, cn_1.cn)(
|
|
321
|
+
// The overlay is anchored to the viewport, not to the container the
|
|
322
|
+
// trigger sits in, so this is the one place in the batch where a
|
|
323
|
+
// viewport breakpoint is the correct signal. A `@min-[…]` here would
|
|
324
|
+
// read the trigger's width, which has nothing to do with the space
|
|
325
|
+
// the overlay actually has.
|
|
326
|
+
"fixed inset-0 z-50 flex items-start justify-center px-3 py-12 md:px-8 md:py-[12vh]", !open && "hidden"), children: [(0, jsx_runtime_1.jsx)("div", { "aria-hidden": "true", onClick: close, className: "absolute inset-0 bg-[var(--color-overlay,rgba(16,25,40,0.56))]" }), (0, jsx_runtime_1.jsxs)("div", { ref: dialogRef, role: "dialog", "aria-modal": "true", "aria-label": dialogLabel, onKeyDown: handleDialogKeyDown, className: "relative flex max-h-full w-full max-w-[640px] flex-col overflow-hidden rounded-xl border border-surface-border bg-surface shadow-soft-xl", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 border-b border-surface-border px-3 py-2 text-on-surface-muted", children: [(0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: "search", size: "md", className: "shrink-0 text-grey-500" }), (0, jsx_runtime_1.jsx)("label", { htmlFor: inputId, className: "sr-only", children: searchLabel }), (0, jsx_runtime_1.jsx)("input", { ref: inputRef, id: inputId, type: "search", value: query, placeholder: searchPlaceholder, autoComplete: "off", "aria-controls": listId, "aria-describedby": hintId, onChange: (event) => {
|
|
327
|
+
setQuery(event.target.value);
|
|
328
|
+
onQueryChange?.(event.target.value);
|
|
329
|
+
}, onKeyDown: handleInputKeyDown, className: (0, cn_1.cn)(
|
|
330
|
+
// No `focus:outline-none` here: it wins over the focus-visible
|
|
331
|
+
// ring below and leaves the field with no visible indicator at
|
|
332
|
+
// all, which a tab walk measured before this comment existed.
|
|
333
|
+
"min-h-10 w-full min-w-0 rounded-lg bg-surface px-1 py-2 text-body-md text-grey-900 placeholder:text-grey-500", FOCUS_RING) }), (0, jsx_runtime_1.jsxs)("button", { type: "button", onClick: close, className: (0, cn_1.cn)("inline-flex min-h-11 min-w-11 shrink-0 cursor-pointer items-center justify-center rounded-lg text-grey-500 hover:bg-surface-muted hover:text-grey-900", FOCUS_RING), children: [(0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: "multiply", size: "md" }), (0, jsx_runtime_1.jsx)("span", { className: "sr-only", children: closeLabel })] })] }), (0, jsx_runtime_1.jsx)("p", { id: hintId, className: "sr-only", children: searchHint }), (0, jsx_runtime_1.jsx)("div", { id: listId, className: "flex min-h-0 max-h-[min(60vh,420px)] flex-col overflow-y-auto", children: renderBody() }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap items-center gap-x-4 gap-y-1 border-t border-surface-border px-4 py-2 text-body-xs text-grey-500", children: [(0, jsx_runtime_1.jsx)("p", { role: "status", "aria-live": "polite", className: "min-w-0 break-words", children: countText }), footer] })] })] })] }));
|
|
334
|
+
}
|