@kodffe/ui 0.0.0-stage → 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/dist/_virtual/_rolldown/runtime.js +11 -0
- package/dist/accordion/accordion.d.ts +44 -0
- package/dist/accordion/accordion.js +84 -0
- package/dist/accordion/accordion.js.map +1 -0
- package/dist/alert/alert.d.ts +17 -0
- package/dist/alert/alert.js +59 -0
- package/dist/alert/alert.js.map +1 -0
- package/dist/app-shell/app-footer.d.ts +29 -0
- package/dist/app-shell/app-footer.js +39 -0
- package/dist/app-shell/app-footer.js.map +1 -0
- package/dist/app-shell/app-shell-context.d.ts +10 -0
- package/dist/app-shell/app-shell-context.js +12 -0
- package/dist/app-shell/app-shell-context.js.map +1 -0
- package/dist/app-shell/app-shell.d.ts +42 -0
- package/dist/app-shell/app-shell.js +191 -0
- package/dist/app-shell/app-shell.js.map +1 -0
- package/dist/app-shell/floating-actions.d.ts +19 -0
- package/dist/app-shell/floating-actions.js +59 -0
- package/dist/app-shell/floating-actions.js.map +1 -0
- package/dist/app-shell/workspace-switcher.d.ts +25 -0
- package/dist/app-shell/workspace-switcher.js +82 -0
- package/dist/app-shell/workspace-switcher.js.map +1 -0
- package/dist/badge/badge.d.ts +19 -0
- package/dist/badge/badge.js +59 -0
- package/dist/badge/badge.js.map +1 -0
- package/dist/banner/banner.d.ts +22 -0
- package/dist/banner/banner.js +80 -0
- package/dist/banner/banner.js.map +1 -0
- package/dist/breadcrumbs/breadcrumbs.d.ts +18 -0
- package/dist/breadcrumbs/breadcrumbs.js +45 -0
- package/dist/breadcrumbs/breadcrumbs.js.map +1 -0
- package/dist/button/button.d.ts +38 -0
- package/dist/button/button.js +83 -0
- package/dist/button/button.js.map +1 -0
- package/dist/card/card.d.ts +159 -0
- package/dist/card/card.js +390 -0
- package/dist/card/card.js.map +1 -0
- package/dist/card/insight-card.d.ts +19 -0
- package/dist/card/insight-card.js +51 -0
- package/dist/card/insight-card.js.map +1 -0
- package/dist/card/integration-card.d.ts +19 -0
- package/dist/card/integration-card.js +70 -0
- package/dist/card/integration-card.js.map +1 -0
- package/dist/charts/charts.d.ts +75 -0
- package/dist/charts/charts.js +453 -0
- package/dist/charts/charts.js.map +1 -0
- package/dist/choice/choice.d.ts +39 -0
- package/dist/choice/choice.js +143 -0
- package/dist/choice/choice.js.map +1 -0
- package/dist/combobox/combobox.d.ts +46 -0
- package/dist/combobox/combobox.js +196 -0
- package/dist/combobox/combobox.js.map +1 -0
- package/dist/command-palette/command-palette.d.ts +35 -0
- package/dist/command-palette/command-palette.js +164 -0
- package/dist/command-palette/command-palette.js.map +1 -0
- package/dist/confirm-dialog/confirm-dialog.d.ts +37 -0
- package/dist/confirm-dialog/confirm-dialog.js +106 -0
- package/dist/confirm-dialog/confirm-dialog.js.map +1 -0
- package/dist/content/assistant.d.ts +86 -0
- package/dist/content/assistant.js +213 -0
- package/dist/content/assistant.js.map +1 -0
- package/dist/content/content.d.ts +45 -0
- package/dist/content/content.js +136 -0
- package/dist/content/content.js.map +1 -0
- package/dist/data-display/avatar-sizes.d.ts +8 -0
- package/dist/data-display/avatar-sizes.js +12 -0
- package/dist/data-display/avatar-sizes.js.map +1 -0
- package/dist/data-display/avatar.d.ts +21 -0
- package/dist/data-display/avatar.js +53 -0
- package/dist/data-display/avatar.js.map +1 -0
- package/dist/data-display/chip.d.ts +20 -0
- package/dist/data-display/chip.js +64 -0
- package/dist/data-display/chip.js.map +1 -0
- package/dist/data-display/code-block.d.ts +14 -0
- package/dist/data-display/code-block.js +50 -0
- package/dist/data-display/code-block.js.map +1 -0
- package/dist/data-display/data-display.d.ts +73 -0
- package/dist/data-display/data-display.js +227 -0
- package/dist/data-display/data-display.js.map +1 -0
- package/dist/data-display/insights.d.ts +120 -0
- package/dist/data-display/insights.js +220 -0
- package/dist/data-display/insights.js.map +1 -0
- package/dist/data-table/cells.d.ts +86 -0
- package/dist/data-table/cells.js +163 -0
- package/dist/data-table/cells.js.map +1 -0
- package/dist/data-table/data-table.d.ts +112 -0
- package/dist/data-table/data-table.js +558 -0
- package/dist/data-table/data-table.js.map +1 -0
- package/dist/date-picker/date-picker.d.ts +61 -0
- package/dist/date-picker/date-picker.js +309 -0
- package/dist/date-picker/date-picker.js.map +1 -0
- package/dist/drawer/drawer.d.ts +32 -0
- package/dist/drawer/drawer.js +72 -0
- package/dist/drawer/drawer.js.map +1 -0
- package/dist/empty-state/empty-state.d.ts +25 -0
- package/dist/empty-state/empty-state.js +78 -0
- package/dist/empty-state/empty-state.js.map +1 -0
- package/dist/error-state/error-state.d.ts +19 -0
- package/dist/error-state/error-state.js +56 -0
- package/dist/error-state/error-state.js.map +1 -0
- package/dist/event-calendar/calendar-logic.test.d.ts +1 -0
- package/dist/event-calendar/dates.d.ts +35 -0
- package/dist/event-calendar/dates.js +55 -0
- package/dist/event-calendar/dates.js.map +1 -0
- package/dist/event-calendar/event-calendar.d.ts +125 -0
- package/dist/event-calendar/event-calendar.js +795 -0
- package/dist/event-calendar/event-calendar.js.map +1 -0
- package/dist/event-calendar/event-details.d.ts +50 -0
- package/dist/event-calendar/event-details.js +124 -0
- package/dist/event-calendar/event-details.js.map +1 -0
- package/dist/event-calendar/layout.d.ts +48 -0
- package/dist/event-calendar/layout.js +55 -0
- package/dist/event-calendar/layout.js.map +1 -0
- package/dist/file-upload/file-upload.d.ts +70 -0
- package/dist/file-upload/file-upload.js +307 -0
- package/dist/file-upload/file-upload.js.map +1 -0
- package/dist/filters/filters.d.ts +48 -0
- package/dist/filters/filters.js +103 -0
- package/dist/filters/filters.js.map +1 -0
- package/dist/form-field/form-field.d.ts +39 -0
- package/dist/form-field/form-field.js +88 -0
- package/dist/form-field/form-field.js.map +1 -0
- package/dist/hover-card/hover-card.d.ts +15 -0
- package/dist/hover-card/hover-card.js +27 -0
- package/dist/hover-card/hover-card.js.map +1 -0
- package/dist/hover-card/person-hover-card.d.ts +26 -0
- package/dist/hover-card/person-hover-card.js +85 -0
- package/dist/hover-card/person-hover-card.js.map +1 -0
- package/dist/icon/icon-tile.d.ts +20 -0
- package/dist/icon/icon-tile.js +55 -0
- package/dist/icon/icon-tile.js.map +1 -0
- package/dist/icon/icon.d.ts +14 -0
- package/dist/icon/icon.js +28 -0
- package/dist/icon/icon.js.map +1 -0
- package/dist/icon/icons.generated.d.ts +358 -0
- package/dist/icon/icons.generated.js +362 -0
- package/dist/icon/icons.generated.js.map +1 -0
- package/dist/index.d.ts +90 -0
- package/dist/index.js +88 -0
- package/dist/input/extra-inputs.d.ts +122 -0
- package/dist/input/extra-inputs.js +351 -0
- package/dist/input/extra-inputs.js.map +1 -0
- package/dist/input/field-styles.d.ts +5 -0
- package/dist/input/field-styles.js +14 -0
- package/dist/input/field-styles.js.map +1 -0
- package/dist/input/input.d.ts +50 -0
- package/dist/input/input.js +107 -0
- package/dist/input/input.js.map +1 -0
- package/dist/layout/layout.d.ts +41 -0
- package/dist/layout/layout.js +90 -0
- package/dist/layout/layout.js.map +1 -0
- package/dist/lib/control-styles.d.ts +9 -0
- package/dist/lib/control-styles.js +16 -0
- package/dist/lib/control-styles.js.map +1 -0
- package/dist/lib/cx.d.ts +2 -0
- package/dist/lib/cx.js +8 -0
- package/dist/lib/cx.js.map +1 -0
- package/dist/lib/glyphs.d.ts +13 -0
- package/dist/lib/glyphs.js +67 -0
- package/dist/lib/glyphs.js.map +1 -0
- package/dist/lib/segmented-styles.d.ts +8 -0
- package/dist/lib/segmented-styles.js +12 -0
- package/dist/lib/segmented-styles.js.map +1 -0
- package/dist/lib/select-on-arrow.d.ts +7 -0
- package/dist/lib/select-on-arrow.js +21 -0
- package/dist/lib/select-on-arrow.js.map +1 -0
- package/dist/lib/skip-link.d.ts +5 -0
- package/dist/lib/skip-link.js +13 -0
- package/dist/lib/skip-link.js.map +1 -0
- package/dist/lib/use-media-query.d.ts +4 -0
- package/dist/lib/use-media-query.js +15 -0
- package/dist/lib/use-media-query.js.map +1 -0
- package/dist/lists/lists.d.ts +76 -0
- package/dist/lists/lists.js +133 -0
- package/dist/lists/lists.js.map +1 -0
- package/dist/locale-switch/locale-switch.d.ts +29 -0
- package/dist/locale-switch/locale-switch.js +62 -0
- package/dist/locale-switch/locale-switch.js.map +1 -0
- package/dist/logo/logo.d.ts +31 -0
- package/dist/logo/logo.js +157 -0
- package/dist/logo/logo.js.map +1 -0
- package/dist/logo/product-logo.d.ts +19 -0
- package/dist/logo/product-logo.js +46 -0
- package/dist/logo/product-logo.js.map +1 -0
- package/dist/marketing/marketing.d.ts +176 -0
- package/dist/marketing/marketing.js +451 -0
- package/dist/marketing/marketing.js.map +1 -0
- package/dist/marketing/newsletter-form.d.ts +21 -0
- package/dist/marketing/newsletter-form.js +100 -0
- package/dist/marketing/newsletter-form.js.map +1 -0
- package/dist/mascot/mascot.d.ts +28 -0
- package/dist/mascot/mascot.js +28 -0
- package/dist/mascot/mascot.js.map +1 -0
- package/dist/mascot/mascots.generated.d.ts +284 -0
- package/dist/mascot/mascots.generated.js +287 -0
- package/dist/mascot/mascots.generated.js.map +1 -0
- package/dist/master-detail/master-detail.d.ts +30 -0
- package/dist/master-detail/master-detail.js +71 -0
- package/dist/master-detail/master-detail.js.map +1 -0
- package/dist/menu/account-menu.d.ts +44 -0
- package/dist/menu/account-menu.js +78 -0
- package/dist/menu/account-menu.js.map +1 -0
- package/dist/menu/context-menu.d.ts +31 -0
- package/dist/menu/context-menu.js +111 -0
- package/dist/menu/context-menu.js.map +1 -0
- package/dist/menu/dropdown-menu.d.ts +49 -0
- package/dist/menu/dropdown-menu.js +152 -0
- package/dist/menu/dropdown-menu.js.map +1 -0
- package/dist/menu/menu-styles.d.ts +8 -0
- package/dist/menu/menu-styles.js +6 -0
- package/dist/menu/menu-styles.js.map +1 -0
- package/dist/menu/menubar.d.ts +31 -0
- package/dist/menu/menubar.js +125 -0
- package/dist/menu/menubar.js.map +1 -0
- package/dist/modal/modal.d.ts +34 -0
- package/dist/modal/modal.js +58 -0
- package/dist/modal/modal.js.map +1 -0
- package/dist/notification-center/notification-center.d.ts +51 -0
- package/dist/notification-center/notification-center.js +244 -0
- package/dist/notification-center/notification-center.js.map +1 -0
- package/dist/otp-input/otp-input.d.ts +23 -0
- package/dist/otp-input/otp-input.js +61 -0
- package/dist/otp-input/otp-input.js.map +1 -0
- package/dist/overlay/overlay.d.ts +53 -0
- package/dist/overlay/overlay.js +103 -0
- package/dist/overlay/overlay.js.map +1 -0
- package/dist/page-header/page-header.d.ts +55 -0
- package/dist/page-header/page-header.js +114 -0
- package/dist/page-header/page-header.js.map +1 -0
- package/dist/page-header/record-headers.d.ts +51 -0
- package/dist/page-header/record-headers.js +134 -0
- package/dist/page-header/record-headers.js.map +1 -0
- package/dist/page-header/section-header.d.ts +21 -0
- package/dist/page-header/section-header.js +44 -0
- package/dist/page-header/section-header.js.map +1 -0
- package/dist/page-navigation/page-navigation.d.ts +59 -0
- package/dist/page-navigation/page-navigation.js +136 -0
- package/dist/page-navigation/page-navigation.js.map +1 -0
- package/dist/pagination/pagination.d.ts +28 -0
- package/dist/pagination/pagination.js +102 -0
- package/dist/pagination/pagination.js.map +1 -0
- package/dist/phone-input/phone-input.d.ts +34 -0
- package/dist/phone-input/phone-input.js +171 -0
- package/dist/phone-input/phone-input.js.map +1 -0
- package/dist/popover/popover.d.ts +23 -0
- package/dist/popover/popover.js +40 -0
- package/dist/popover/popover.js.map +1 -0
- package/dist/progress/progress.d.ts +21 -0
- package/dist/progress/progress.js +49 -0
- package/dist/progress/progress.js.map +1 -0
- package/dist/segmented-control/segmented-control.d.ts +32 -0
- package/dist/segmented-control/segmented-control.js +29 -0
- package/dist/segmented-control/segmented-control.js.map +1 -0
- package/dist/select/select.d.ts +48 -0
- package/dist/select/select.js +136 -0
- package/dist/select/select.js.map +1 -0
- package/dist/settings/permission-matrix.d.ts +29 -0
- package/dist/settings/permission-matrix.js +101 -0
- package/dist/settings/permission-matrix.js.map +1 -0
- package/dist/settings/settings-row.d.ts +32 -0
- package/dist/settings/settings-row.js +63 -0
- package/dist/settings/settings-row.js.map +1 -0
- package/dist/side-nav/side-nav.d.ts +36 -0
- package/dist/side-nav/side-nav.js +123 -0
- package/dist/side-nav/side-nav.js.map +1 -0
- package/dist/site-header/site-header.d.ts +32 -0
- package/dist/site-header/site-header.js +99 -0
- package/dist/site-header/site-header.js.map +1 -0
- package/dist/skeleton/skeleton.d.ts +16 -0
- package/dist/skeleton/skeleton.js +19 -0
- package/dist/skeleton/skeleton.js.map +1 -0
- package/dist/slider/slider.d.ts +15 -0
- package/dist/slider/slider.js +48 -0
- package/dist/slider/slider.js.map +1 -0
- package/dist/spinner/spinner.d.ts +15 -0
- package/dist/spinner/spinner.js +42 -0
- package/dist/spinner/spinner.js.map +1 -0
- package/dist/stepper/step-dots.d.ts +16 -0
- package/dist/stepper/step-dots.js +26 -0
- package/dist/stepper/step-dots.js.map +1 -0
- package/dist/stepper/stepper.d.ts +26 -0
- package/dist/stepper/stepper.js +113 -0
- package/dist/stepper/stepper.js.map +1 -0
- package/dist/tabs/tabs.d.ts +31 -0
- package/dist/tabs/tabs.js +66 -0
- package/dist/tabs/tabs.js.map +1 -0
- package/dist/templates/app-templates.d.ts +126 -0
- package/dist/templates/app-templates.js +153 -0
- package/dist/templates/app-templates.js.map +1 -0
- package/dist/templates/site-templates.d.ts +49 -0
- package/dist/templates/site-templates.js +110 -0
- package/dist/templates/site-templates.js.map +1 -0
- package/dist/toast/toast-store.d.ts +54 -0
- package/dist/toast/toast-store.js +49 -0
- package/dist/toast/toast-store.js.map +1 -0
- package/dist/toast/toaster.d.ts +15 -0
- package/dist/toast/toaster.js +124 -0
- package/dist/toast/toaster.js.map +1 -0
- package/dist/tooltip/tooltip.d.ts +29 -0
- package/dist/tooltip/tooltip.js +54 -0
- package/dist/tooltip/tooltip.js.map +1 -0
- package/package.json +88 -3
- package/styles.css +521 -0
- package/README.md +0 -3
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as Primitive from '@radix-ui/react-menubar';
|
|
2
|
+
import type { ComponentPropsWithoutRef, ReactNode } from 'react';
|
|
3
|
+
import { type IconName } from '../icon/icon';
|
|
4
|
+
/**
|
|
5
|
+
* Desktop application menu bar (File, Edit, View) for editor-like products (workflow builder).
|
|
6
|
+
* Not for site navigation. Hide it on mobile and expose the same actions through a DropdownMenu.
|
|
7
|
+
*/
|
|
8
|
+
export declare function Menubar({ className, ...rest }: ComponentPropsWithoutRef<typeof Primitive.Root>): import("react").JSX.Element;
|
|
9
|
+
export declare const MenubarMenu: typeof Primitive.Menu;
|
|
10
|
+
export declare function MenubarTrigger({ className, ...rest }: ComponentPropsWithoutRef<typeof Primitive.Trigger>): import("react").JSX.Element;
|
|
11
|
+
export declare function MenubarContent({ className, sideOffset, align, collisionPadding, ...rest }: ComponentPropsWithoutRef<typeof Primitive.Content>): import("react").JSX.Element;
|
|
12
|
+
interface ItemExtras {
|
|
13
|
+
icon?: IconName;
|
|
14
|
+
/** Keyboard shortcut hint, e.g. `⌘D`. */
|
|
15
|
+
shortcut?: string;
|
|
16
|
+
tone?: 'default' | 'danger';
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
}
|
|
19
|
+
export declare function MenubarItem({ icon, shortcut, tone, className, children, ...rest }: ComponentPropsWithoutRef<typeof Primitive.Item> & ItemExtras): import("react").JSX.Element;
|
|
20
|
+
export declare function MenubarCheckboxItem({ className, children, ...rest }: ComponentPropsWithoutRef<typeof Primitive.CheckboxItem>): import("react").JSX.Element;
|
|
21
|
+
export declare const MenubarRadioGroup: import("react").ForwardRefExoticComponent<Primitive.MenubarRadioGroupProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
22
|
+
export declare function MenubarRadioItem({ className, children, ...rest }: ComponentPropsWithoutRef<typeof Primitive.RadioItem>): import("react").JSX.Element;
|
|
23
|
+
export declare function MenubarLabel({ className, ...rest }: ComponentPropsWithoutRef<typeof Primitive.Label>): import("react").JSX.Element;
|
|
24
|
+
export declare function MenubarSeparator({ className, ...rest }: ComponentPropsWithoutRef<typeof Primitive.Separator>): import("react").JSX.Element;
|
|
25
|
+
export declare const MenubarGroup: import("react").ForwardRefExoticComponent<Primitive.MenubarGroupProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
26
|
+
export declare const MenubarSub: import("react").FC<Primitive.MenubarSubProps>;
|
|
27
|
+
export declare function MenubarSubTrigger({ icon, className, children, ...rest }: ComponentPropsWithoutRef<typeof Primitive.SubTrigger> & {
|
|
28
|
+
icon?: IconName;
|
|
29
|
+
}): import("react").JSX.Element;
|
|
30
|
+
export declare function MenubarSubContent({ className, ...rest }: ComponentPropsWithoutRef<typeof Primitive.SubContent>): import("react").JSX.Element;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cx as e } from "../lib/cx.js";
|
|
3
|
+
import { Icon as t } from "../icon/icon.js";
|
|
4
|
+
import { Glyph as n } from "../lib/glyphs.js";
|
|
5
|
+
import { menuContent as r, menuIndicatorSlot as i, menuItem as a, menuLabel as o, menuSeparator as s } from "./menu-styles.js";
|
|
6
|
+
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
7
|
+
import * as u from "@radix-ui/react-menubar";
|
|
8
|
+
//#region src/menu/menubar.tsx
|
|
9
|
+
function d({ className: t, ...n }) {
|
|
10
|
+
return /* @__PURE__ */ c(u.Root, {
|
|
11
|
+
className: e("flex gap-0.5 rounded-md border border-border bg-surface p-1 font-sans", t),
|
|
12
|
+
...n
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
var f = u.Menu;
|
|
16
|
+
function p({ className: t, ...n }) {
|
|
17
|
+
return /* @__PURE__ */ c(u.Trigger, {
|
|
18
|
+
className: e("cursor-pointer rounded-sm border-0 bg-transparent px-3 py-1.5 font-sans text-sm font-medium text-fg outline-none", "data-[highlighted]:bg-surface-muted data-[state=open]:bg-surface-muted focus-visible:outline-3 focus-visible:outline-focus", t),
|
|
19
|
+
...n
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function m({ className: t, sideOffset: n = 6, align: i = "start", collisionPadding: a = 16, ...o }) {
|
|
23
|
+
return /* @__PURE__ */ c(u.Portal, { children: /* @__PURE__ */ c(u.Content, {
|
|
24
|
+
sideOffset: n,
|
|
25
|
+
align: i,
|
|
26
|
+
collisionPadding: a,
|
|
27
|
+
className: e(r, "[--kf-menu-max-h:var(--radix-menubar-content-available-height)]", t),
|
|
28
|
+
...o
|
|
29
|
+
}) });
|
|
30
|
+
}
|
|
31
|
+
function h({ icon: n, shortcut: r, tone: i = "default", className: o, children: s, ...d }) {
|
|
32
|
+
return /* @__PURE__ */ l(u.Item, {
|
|
33
|
+
className: e(a, i === "danger" && "text-danger-fg data-[highlighted]:bg-danger-surface", o),
|
|
34
|
+
...d,
|
|
35
|
+
children: [
|
|
36
|
+
n && /* @__PURE__ */ c(t, {
|
|
37
|
+
name: n,
|
|
38
|
+
size: 20,
|
|
39
|
+
className: "shrink-0"
|
|
40
|
+
}),
|
|
41
|
+
/* @__PURE__ */ c("span", {
|
|
42
|
+
className: "min-w-0 flex-1 truncate",
|
|
43
|
+
children: s
|
|
44
|
+
}),
|
|
45
|
+
r && /* @__PURE__ */ c("span", {
|
|
46
|
+
className: "ml-auto pl-4 font-mono text-xs text-fg-muted",
|
|
47
|
+
children: r
|
|
48
|
+
})
|
|
49
|
+
]
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function g({ className: t, children: r, ...o }) {
|
|
53
|
+
return /* @__PURE__ */ l(u.CheckboxItem, {
|
|
54
|
+
className: e(a, i, t),
|
|
55
|
+
...o,
|
|
56
|
+
children: [/* @__PURE__ */ c(u.ItemIndicator, {
|
|
57
|
+
className: "absolute left-2.5 inline-flex text-link",
|
|
58
|
+
children: /* @__PURE__ */ c(n, {
|
|
59
|
+
name: "check",
|
|
60
|
+
size: 16
|
|
61
|
+
})
|
|
62
|
+
}), r]
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
var _ = u.RadioGroup;
|
|
66
|
+
function v({ className: t, children: r, ...o }) {
|
|
67
|
+
return /* @__PURE__ */ l(u.RadioItem, {
|
|
68
|
+
className: e(a, i, t),
|
|
69
|
+
...o,
|
|
70
|
+
children: [/* @__PURE__ */ c(u.ItemIndicator, {
|
|
71
|
+
className: "absolute left-3 inline-flex text-link",
|
|
72
|
+
children: /* @__PURE__ */ c(n, {
|
|
73
|
+
name: "dot",
|
|
74
|
+
size: 14
|
|
75
|
+
})
|
|
76
|
+
}), r]
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function y({ className: t, ...n }) {
|
|
80
|
+
return /* @__PURE__ */ c(u.Label, {
|
|
81
|
+
className: e(o, t),
|
|
82
|
+
...n
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function b({ className: t, ...n }) {
|
|
86
|
+
return /* @__PURE__ */ c(u.Separator, {
|
|
87
|
+
className: e(s, t),
|
|
88
|
+
...n
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
var x = u.Group, S = u.Sub;
|
|
92
|
+
function C({ icon: r, className: i, children: o, ...s }) {
|
|
93
|
+
return /* @__PURE__ */ l(u.SubTrigger, {
|
|
94
|
+
className: e(a, i),
|
|
95
|
+
...s,
|
|
96
|
+
children: [
|
|
97
|
+
r && /* @__PURE__ */ c(t, {
|
|
98
|
+
name: r,
|
|
99
|
+
size: 20,
|
|
100
|
+
className: "shrink-0"
|
|
101
|
+
}),
|
|
102
|
+
/* @__PURE__ */ c("span", {
|
|
103
|
+
className: "flex-1",
|
|
104
|
+
children: o
|
|
105
|
+
}),
|
|
106
|
+
/* @__PURE__ */ c(n, {
|
|
107
|
+
name: "chevron-right",
|
|
108
|
+
size: 16,
|
|
109
|
+
className: "text-fg-muted"
|
|
110
|
+
})
|
|
111
|
+
]
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
function w({ className: t, ...n }) {
|
|
115
|
+
return /* @__PURE__ */ c(u.Portal, { children: /* @__PURE__ */ c(u.SubContent, {
|
|
116
|
+
sideOffset: 4,
|
|
117
|
+
collisionPadding: 16,
|
|
118
|
+
className: e(r, t),
|
|
119
|
+
...n
|
|
120
|
+
}) });
|
|
121
|
+
}
|
|
122
|
+
//#endregion
|
|
123
|
+
export { d as Menubar, g as MenubarCheckboxItem, m as MenubarContent, x as MenubarGroup, h as MenubarItem, y as MenubarLabel, f as MenubarMenu, _ as MenubarRadioGroup, v as MenubarRadioItem, b as MenubarSeparator, S as MenubarSub, w as MenubarSubContent, C as MenubarSubTrigger, p as MenubarTrigger };
|
|
124
|
+
|
|
125
|
+
//# sourceMappingURL=menubar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menubar.js","names":["Primitive","Menubar","rest","cx","className","MenubarMenu","MenubarTrigger","MenubarContent","menuContent","MenubarItem","menuItem","tone","icon","Icon","shortcut","MenubarCheckboxItem","menuIndicatorSlot","Glyph","children","MenubarRadioGroup","MenubarRadioItem","MenubarLabel","menuLabel","MenubarSeparator","menuSeparator","MenubarGroup","MenubarSub","MenubarSubTrigger","MenubarSubContent"],"sources":["../../src/menu/menubar.tsx"],"sourcesContent":["// Shares its item components' structure with the other menu files (dropdown-menu, context-menu, menubar): keep them in sync.\n'use client';\n\nimport * as Primitive from '@radix-ui/react-menubar';\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react';\nimport { cx } from '../lib/cx';\nimport { Icon, type IconName } from '../icon/icon';\nimport { Glyph } from '../lib/glyphs';\nimport {\n menuContent,\n menuIndicatorSlot,\n menuItem,\n menuItemDanger,\n menuLabel,\n menuSeparator,\n menuShortcut,\n} from './menu-styles';\n\n/**\n * Desktop application menu bar (File, Edit, View) for editor-like products (workflow builder).\n * Not for site navigation. Hide it on mobile and expose the same actions through a DropdownMenu.\n */\nexport function Menubar({ className, ...rest }: ComponentPropsWithoutRef<typeof Primitive.Root>) {\n return (\n <Primitive.Root\n className={cx('flex gap-0.5 rounded-md border border-border bg-surface p-1 font-sans', className)}\n {...rest}\n />\n );\n}\n\nexport const MenubarMenu: typeof Primitive.Menu = Primitive.Menu;\n\nexport function MenubarTrigger({ className, ...rest }: ComponentPropsWithoutRef<typeof Primitive.Trigger>) {\n return (\n <Primitive.Trigger\n className={cx(\n 'cursor-pointer rounded-sm border-0 bg-transparent px-3 py-1.5 font-sans text-sm font-medium text-fg outline-none',\n 'data-[highlighted]:bg-surface-muted data-[state=open]:bg-surface-muted focus-visible:outline-3 focus-visible:outline-focus',\n className,\n )}\n {...rest}\n />\n );\n}\n\nexport function MenubarContent({\n className,\n sideOffset = 6,\n align = 'start',\n collisionPadding = 16,\n ...rest\n}: ComponentPropsWithoutRef<typeof Primitive.Content>) {\n return (\n <Primitive.Portal>\n <Primitive.Content\n sideOffset={sideOffset}\n align={align}\n collisionPadding={collisionPadding}\n className={cx(menuContent, '[--kf-menu-max-h:var(--radix-menubar-content-available-height)]', className)}\n {...rest}\n />\n </Primitive.Portal>\n );\n}\n\ninterface ItemExtras {\n icon?: IconName;\n /** Keyboard shortcut hint, e.g. `⌘D`. */\n shortcut?: string;\n tone?: 'default' | 'danger';\n children: ReactNode;\n}\n\nexport function MenubarItem({\n icon,\n shortcut,\n tone = 'default',\n className,\n children,\n ...rest\n}: ComponentPropsWithoutRef<typeof Primitive.Item> & ItemExtras) {\n return (\n <Primitive.Item className={cx(menuItem, tone === 'danger' && menuItemDanger, className)} {...rest}>\n {icon && <Icon name={icon} size={20} className=\"shrink-0\" />}\n <span className=\"min-w-0 flex-1 truncate\">{children}</span>\n {shortcut && <span className={menuShortcut}>{shortcut}</span>}\n </Primitive.Item>\n );\n}\n\nexport function MenubarCheckboxItem({\n className,\n children,\n ...rest\n}: ComponentPropsWithoutRef<typeof Primitive.CheckboxItem>) {\n return (\n <Primitive.CheckboxItem className={cx(menuItem, menuIndicatorSlot, className)} {...rest}>\n <Primitive.ItemIndicator className=\"absolute left-2.5 inline-flex text-link\">\n <Glyph name=\"check\" size={16} />\n </Primitive.ItemIndicator>\n {children}\n </Primitive.CheckboxItem>\n );\n}\n\nexport const MenubarRadioGroup = Primitive.RadioGroup;\n\nexport function MenubarRadioItem({\n className,\n children,\n ...rest\n}: ComponentPropsWithoutRef<typeof Primitive.RadioItem>) {\n return (\n <Primitive.RadioItem className={cx(menuItem, menuIndicatorSlot, className)} {...rest}>\n <Primitive.ItemIndicator className=\"absolute left-3 inline-flex text-link\">\n <Glyph name=\"dot\" size={14} />\n </Primitive.ItemIndicator>\n {children}\n </Primitive.RadioItem>\n );\n}\n\nexport function MenubarLabel({ className, ...rest }: ComponentPropsWithoutRef<typeof Primitive.Label>) {\n return <Primitive.Label className={cx(menuLabel, className)} {...rest} />;\n}\n\nexport function MenubarSeparator({ className, ...rest }: ComponentPropsWithoutRef<typeof Primitive.Separator>) {\n return <Primitive.Separator className={cx(menuSeparator, className)} {...rest} />;\n}\n\nexport const MenubarGroup = Primitive.Group;\nexport const MenubarSub = Primitive.Sub;\n\nexport function MenubarSubTrigger({\n icon,\n className,\n children,\n ...rest\n}: ComponentPropsWithoutRef<typeof Primitive.SubTrigger> & { icon?: IconName }) {\n return (\n <Primitive.SubTrigger className={cx(menuItem, className)} {...rest}>\n {icon && <Icon name={icon} size={20} className=\"shrink-0\" />}\n <span className=\"flex-1\">{children}</span>\n <Glyph name=\"chevron-right\" size={16} className=\"text-fg-muted\" />\n </Primitive.SubTrigger>\n );\n}\n\nexport function MenubarSubContent({ className, ...rest }: ComponentPropsWithoutRef<typeof Primitive.SubContent>) {\n return (\n <Primitive.Portal>\n <Primitive.SubContent sideOffset={4} collisionPadding={16} className={cx(menuContent, className)} {...rest} />\n </Primitive.Portal>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as Dialog from '@radix-ui/react-dialog';
|
|
2
|
+
import { type ComponentPropsWithoutRef, type ReactNode } from 'react';
|
|
3
|
+
export type ModalSize = 'sm' | 'md' | 'lg' | 'xl';
|
|
4
|
+
export interface ModalProps {
|
|
5
|
+
/** Controlled open state. */
|
|
6
|
+
open?: boolean;
|
|
7
|
+
defaultOpen?: boolean;
|
|
8
|
+
onOpenChange?: (open: boolean) => void;
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Dialog that interrupts the current task. Centered on desktop; a bottom sheet with a drag
|
|
13
|
+
* handle below 640px. Built on Radix Dialog: focus trap, Escape, scroll lock, focus return.
|
|
14
|
+
*/
|
|
15
|
+
export declare function Modal({ open: openProp, defaultOpen, onOpenChange, children }: ModalProps): import("react").JSX.Element;
|
|
16
|
+
/** Element that opens the modal. Use `asChild` to render your own Button. */
|
|
17
|
+
export declare const ModalTrigger: import("react").ForwardRefExoticComponent<Dialog.DialogTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
18
|
+
/** Closes the modal. Use `asChild` to wrap a Button (e.g. "Cancel"). */
|
|
19
|
+
export declare const ModalClose: import("react").ForwardRefExoticComponent<Dialog.DialogCloseProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
20
|
+
export interface ModalContentProps extends Omit<ComponentPropsWithoutRef<typeof Dialog.Content>, 'title' | 'asChild'> {
|
|
21
|
+
/** Required for screen readers; hide it visually with `hideTitle`. */
|
|
22
|
+
title: ReactNode;
|
|
23
|
+
description?: ReactNode;
|
|
24
|
+
size?: ModalSize;
|
|
25
|
+
/** Actions row. Buttons stack full-width on mobile; put the primary action last. */
|
|
26
|
+
footer?: ReactNode;
|
|
27
|
+
hideTitle?: boolean;
|
|
28
|
+
hideClose?: boolean;
|
|
29
|
+
/** Accessible label of the close button (translate it for other locales). */
|
|
30
|
+
closeLabel?: string;
|
|
31
|
+
/** Extra classes for the scrollable body. To override its padding use the important modifier (`px-0!`). */
|
|
32
|
+
bodyClassName?: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function ModalContent({ title, description, size, footer, hideTitle, hideClose, closeLabel, bodyClassName, className, children, ...rest }: ModalContentProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cx as e } from "../lib/cx.js";
|
|
3
|
+
import { OverlayBackdrop as t, PanelBody as n, PanelFooter as r, PanelHeader as i, SheetHandle as a, useSwipeDismiss as o } from "../overlay/overlay.js";
|
|
4
|
+
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
5
|
+
import { createContext as l, useContext as u, useState as d } from "react";
|
|
6
|
+
import * as f from "@radix-ui/react-dialog";
|
|
7
|
+
//#region src/modal/modal.tsx
|
|
8
|
+
var p = {
|
|
9
|
+
sm: "sm:max-w-md",
|
|
10
|
+
md: "sm:max-w-xl",
|
|
11
|
+
lg: "sm:max-w-3xl",
|
|
12
|
+
xl: "sm:max-w-5xl"
|
|
13
|
+
}, m = l(() => {});
|
|
14
|
+
function h({ open: e, defaultOpen: t = !1, onOpenChange: n, children: r }) {
|
|
15
|
+
let [i, a] = d(t), o = e ?? i, c = (t) => {
|
|
16
|
+
e === void 0 && a(t), n?.(t);
|
|
17
|
+
};
|
|
18
|
+
return /* @__PURE__ */ s(f.Root, {
|
|
19
|
+
open: o,
|
|
20
|
+
onOpenChange: c,
|
|
21
|
+
children: /* @__PURE__ */ s(m.Provider, {
|
|
22
|
+
value: () => c(!1),
|
|
23
|
+
children: r
|
|
24
|
+
})
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
var g = f.Trigger, _ = f.Close;
|
|
28
|
+
function v({ title: l, description: d, size: h = "md", footer: g, hideTitle: _, hideClose: v, closeLabel: y = "Close", bodyClassName: b, className: x, children: S, ...C }) {
|
|
29
|
+
let w = u(m), { panelRef: T, handlers: E } = o("down", w);
|
|
30
|
+
return /* @__PURE__ */ c(f.Portal, { children: [/* @__PURE__ */ s(t, {}), /* @__PURE__ */ c(f.Content, {
|
|
31
|
+
ref: T,
|
|
32
|
+
...d ? {} : { "aria-describedby": void 0 },
|
|
33
|
+
className: e("kf-modal fixed inset-x-0 bottom-0 z-50 flex max-h-[92dvh] flex-col rounded-t-xl bg-surface font-sans text-fg shadow-overlay", "pb-[env(safe-area-inset-bottom)] focus:outline-none", "sm:inset-0 sm:m-auto sm:h-fit sm:max-h-[min(90dvh,56rem)] sm:w-[calc(100%-2rem)] sm:rounded-xl sm:pb-0", p[h], x),
|
|
34
|
+
...C,
|
|
35
|
+
children: [
|
|
36
|
+
/* @__PURE__ */ s(a, {
|
|
37
|
+
className: "sm:hidden",
|
|
38
|
+
...E
|
|
39
|
+
}),
|
|
40
|
+
/* @__PURE__ */ s(i, {
|
|
41
|
+
title: l,
|
|
42
|
+
description: d,
|
|
43
|
+
hideTitle: _,
|
|
44
|
+
hideClose: v,
|
|
45
|
+
closeLabel: y
|
|
46
|
+
}),
|
|
47
|
+
/* @__PURE__ */ s(n, {
|
|
48
|
+
className: b,
|
|
49
|
+
children: S
|
|
50
|
+
}),
|
|
51
|
+
g && /* @__PURE__ */ s(r, { children: g })
|
|
52
|
+
]
|
|
53
|
+
})] });
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
export { h as Modal, _ as ModalClose, v as ModalContent, g as ModalTrigger };
|
|
57
|
+
|
|
58
|
+
//# sourceMappingURL=modal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modal.js","names":["Dialog","SIZES","CloseContext","createContext","Modal","openProp","uncontrolled","setUncontrolled","useState","defaultOpen","open","setOpen","next","onOpenChange","ModalTrigger","ModalClose","ModalContent","rest","close","useContext","useSwipeDismiss","OverlayBackdrop","panelRef","description","cx","size","className","SheetHandle","handlers","PanelHeader","PanelBody","bodyClassName","footer","PanelFooter"],"sources":["../../src/modal/modal.tsx"],"sourcesContent":["'use client';\n\nimport * as Dialog from '@radix-ui/react-dialog';\nimport { createContext, useContext, useState, type ComponentPropsWithoutRef, type ReactNode } from 'react';\nimport { cx } from '../lib/cx';\nimport { OverlayBackdrop, PanelBody, PanelFooter, PanelHeader, SheetHandle, useSwipeDismiss } from '../overlay/overlay';\n\nexport type ModalSize = 'sm' | 'md' | 'lg' | 'xl';\n\nconst SIZES: Record<ModalSize, string> = {\n sm: 'sm:max-w-md',\n md: 'sm:max-w-xl',\n lg: 'sm:max-w-3xl',\n xl: 'sm:max-w-5xl',\n};\n\nconst CloseContext = createContext<() => void>(() => {});\n\nexport interface ModalProps {\n /** Controlled open state. */\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n children: ReactNode;\n}\n\n/**\n * Dialog that interrupts the current task. Centered on desktop; a bottom sheet with a drag\n * handle below 640px. Built on Radix Dialog: focus trap, Escape, scroll lock, focus return.\n */\nexport function Modal({ open: openProp, defaultOpen = false, onOpenChange, children }: ModalProps) {\n const [uncontrolled, setUncontrolled] = useState(defaultOpen);\n const open = openProp ?? uncontrolled;\n const setOpen = (next: boolean) => {\n if (openProp === undefined) setUncontrolled(next);\n onOpenChange?.(next);\n };\n return (\n <Dialog.Root open={open} onOpenChange={setOpen}>\n <CloseContext.Provider value={() => setOpen(false)}>{children}</CloseContext.Provider>\n </Dialog.Root>\n );\n}\n\n/** Element that opens the modal. Use `asChild` to render your own Button. */\nexport const ModalTrigger = Dialog.Trigger;\n/** Closes the modal. Use `asChild` to wrap a Button (e.g. \"Cancel\"). */\nexport const ModalClose = Dialog.Close;\n\nexport interface ModalContentProps extends Omit<ComponentPropsWithoutRef<typeof Dialog.Content>, 'title' | 'asChild'> {\n /** Required for screen readers; hide it visually with `hideTitle`. */\n title: ReactNode;\n description?: ReactNode;\n size?: ModalSize;\n /** Actions row. Buttons stack full-width on mobile; put the primary action last. */\n footer?: ReactNode;\n hideTitle?: boolean;\n hideClose?: boolean;\n /** Accessible label of the close button (translate it for other locales). */\n closeLabel?: string;\n /** Extra classes for the scrollable body. To override its padding use the important modifier (`px-0!`). */\n bodyClassName?: string;\n}\n\nexport function ModalContent({\n title,\n description,\n size = 'md',\n footer,\n hideTitle,\n hideClose,\n closeLabel = 'Close',\n bodyClassName,\n className,\n children,\n ...rest\n}: ModalContentProps) {\n const close = useContext(CloseContext);\n const { panelRef, handlers } = useSwipeDismiss('down', close);\n return (\n <Dialog.Portal>\n <OverlayBackdrop />\n <Dialog.Content\n ref={panelRef}\n {...(description ? {} : { 'aria-describedby': undefined })}\n className={cx(\n 'kf-modal fixed inset-x-0 bottom-0 z-50 flex max-h-[92dvh] flex-col rounded-t-xl bg-surface font-sans text-fg shadow-overlay',\n 'pb-[env(safe-area-inset-bottom)] focus:outline-none',\n 'sm:inset-0 sm:m-auto sm:h-fit sm:max-h-[min(90dvh,56rem)] sm:w-[calc(100%-2rem)] sm:rounded-xl sm:pb-0',\n SIZES[size],\n className,\n )}\n {...rest}\n >\n <SheetHandle className=\"sm:hidden\" {...handlers} />\n <PanelHeader title={title} description={description} hideTitle={hideTitle} hideClose={hideClose} closeLabel={closeLabel} />\n <PanelBody className={bodyClassName}>{children}</PanelBody>\n {footer && <PanelFooter>{footer}</PanelFooter>}\n </Dialog.Content>\n </Dialog.Portal>\n );\n}\n"],"mappings":";;;;;;;AASA,IAAMC,IAAmC;CACvC,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN,GAEMC,IAAeC,QAAgC,CAAC,CAAC;AAcvD,SAAgBC,EAAM,EAAE,MAAMC,GAAU,iBAAc,IAAO,iBAAc,eAAwB;CACjG,IAAM,CAACC,GAAcC,KAAmBC,EAASC,CAAW,GACtDC,IAAOL,KAAYC,GACnBK,KAAW,MAAkB;EAEjC,AADIN,MAAa,KAAA,KAAWE,EAAgBK,CAAI,GAChDC,IAAeD,CAAI;CACrB;CACA,OACE,kBAACZ,EAAO,MAAR;EAAmB;EAAM,cAAcW;EACrC,UAAA,kBAACT,EAAa,UAAd;GAAuB,aAAaS,EAAQ,EAAK;GAAI;EAAgC,CAAA;CAC1E,CAAA;AAEjB;AAGA,IAAaG,IAAed,EAAO,SAEtBe,IAAaf,EAAO;AAiBjC,SAAgBgB,EAAa,EAC3B,UACA,gBACA,UAAO,MACP,WACA,cACA,cACA,gBAAa,SACb,kBACA,cACA,aACA,GAAGC,KACiB;CACpB,IAAMC,IAAQC,EAAWjB,CAAY,GAC/B,EAAE,aAAU,gBAAakB,EAAgB,QAAQF,CAAK;CAC5D,OACE,kBAAClB,EAAO,QAAR,EAAA,UAAA,CACE,kBAACqB,GAAD,CAAkB,CAAA,GAClB,kBAACrB,EAAO,SAAR;EACE,KAAKsB;EACL,GAAKC,IAAc,CAAC,IAAI,EAAE,oBAAoB,KAAA,EAAU;EACxD,WAAWC,EACT,+HACA,uDACA,0GACAvB,EAAMwB,IACNC,CACF;EACA,GAAIT;EAVN,UAAA;GAYE,kBAACU,GAAD;IAAa,WAAU;IAAY,GAAIC;GAAW,CAAA;GAClD,kBAACC,GAAD;IAAoB;IAAoB;IAAwB;IAAsB;IAAuB;GAAa,CAAA;GAC1H,kBAACC,GAAD;IAAW,WAAWC;IAAgB;GAAoB,CAAA;GACzDC,KAAU,kBAACC,GAAD,EAAA,UAAcD,EAAoB,CAAA;EAC/B;CACH,CAAA,CAAA,EAAA,CAAA;AAEnB"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { type IconName } from '../icon/icon';
|
|
3
|
+
export type NotificationVariant = 'neutral' | 'success' | 'warning' | 'danger' | 'info';
|
|
4
|
+
export interface NotificationItem {
|
|
5
|
+
id: string;
|
|
6
|
+
title: ReactNode;
|
|
7
|
+
description?: ReactNode;
|
|
8
|
+
/** When it happened; shown as relative time ("5 min ago"). */
|
|
9
|
+
time: Date | string | number;
|
|
10
|
+
read?: boolean;
|
|
11
|
+
variant?: NotificationVariant;
|
|
12
|
+
/** Overrides the variant icon. */
|
|
13
|
+
icon?: IconName;
|
|
14
|
+
}
|
|
15
|
+
export interface NotificationCenterProps {
|
|
16
|
+
notifications: NotificationItem[];
|
|
17
|
+
/** Called when the user opens an item. Mark it read here and navigate if needed. */
|
|
18
|
+
onSelect?: (item: NotificationItem) => void;
|
|
19
|
+
onMarkAllRead?: () => void;
|
|
20
|
+
/** Footer content, e.g. a "View all" link or notification settings. */
|
|
21
|
+
footer?: ReactNode;
|
|
22
|
+
/** Shows a skeleton list while the first page loads. */
|
|
23
|
+
loading?: boolean;
|
|
24
|
+
/** Locale for relative times (e.g. 'es'). */
|
|
25
|
+
locale?: string;
|
|
26
|
+
open?: boolean;
|
|
27
|
+
onOpenChange?: (open: boolean) => void;
|
|
28
|
+
/** Translatable strings. */
|
|
29
|
+
labels?: Partial<typeof DEFAULT_LABELS>;
|
|
30
|
+
className?: string;
|
|
31
|
+
}
|
|
32
|
+
declare const DEFAULT_LABELS: {
|
|
33
|
+
title: string;
|
|
34
|
+
/** `{count}` is replaced by the number of unread items. */
|
|
35
|
+
unreadCount: string;
|
|
36
|
+
filter: string;
|
|
37
|
+
all: string;
|
|
38
|
+
unread: string;
|
|
39
|
+
markAllRead: string;
|
|
40
|
+
emptyTitle: string;
|
|
41
|
+
emptyDescription: string;
|
|
42
|
+
emptyUnreadTitle: string;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Bell button with an unread badge that opens the notification list: a popover on desktop,
|
|
46
|
+
* a bottom drawer on mobile. Data and read state stay in your app (pass `notifications`).
|
|
47
|
+
*/
|
|
48
|
+
export declare function NotificationCenter({ notifications, onSelect, onMarkAllRead, footer, loading, locale, open: openProp, onOpenChange, labels: labelOverrides, className, }: NotificationCenterProps): import("react").JSX.Element;
|
|
49
|
+
/** "5 minutes ago", "yesterday", "just now" — in the given locale. */
|
|
50
|
+
export declare function formatRelative(date: Date, locale?: string, now?: number): string;
|
|
51
|
+
export {};
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cx as e } from "../lib/cx.js";
|
|
3
|
+
import { Icon as t } from "../icon/icon.js";
|
|
4
|
+
import { Drawer as n, DrawerContent as r, DrawerTrigger as i } from "../drawer/drawer.js";
|
|
5
|
+
import { DESKTOP_QUERY as a, useMediaQuery as o } from "../lib/use-media-query.js";
|
|
6
|
+
import { Skeleton as s } from "../skeleton/skeleton.js";
|
|
7
|
+
import { EmptyState as c } from "../empty-state/empty-state.js";
|
|
8
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
9
|
+
import { useState as d } from "react";
|
|
10
|
+
import * as f from "@radix-ui/react-popover";
|
|
11
|
+
//#region src/notification-center/notification-center.tsx
|
|
12
|
+
var p = {
|
|
13
|
+
neutral: {
|
|
14
|
+
name: "notify",
|
|
15
|
+
className: "bg-surface-muted text-fg-muted"
|
|
16
|
+
},
|
|
17
|
+
success: {
|
|
18
|
+
name: "accept",
|
|
19
|
+
className: "bg-success-surface text-success-icon"
|
|
20
|
+
},
|
|
21
|
+
warning: {
|
|
22
|
+
name: "warning",
|
|
23
|
+
className: "bg-warning-surface text-warning-icon"
|
|
24
|
+
},
|
|
25
|
+
danger: {
|
|
26
|
+
name: "error",
|
|
27
|
+
className: "bg-danger-surface text-danger-icon"
|
|
28
|
+
},
|
|
29
|
+
info: {
|
|
30
|
+
name: "info",
|
|
31
|
+
className: "bg-info-surface text-info-icon"
|
|
32
|
+
}
|
|
33
|
+
}, m = {
|
|
34
|
+
title: "Notifications",
|
|
35
|
+
unreadCount: "{count} unread",
|
|
36
|
+
filter: "Filter",
|
|
37
|
+
all: "All",
|
|
38
|
+
unread: "Unread",
|
|
39
|
+
markAllRead: "Mark all as read",
|
|
40
|
+
emptyTitle: "You’re all caught up",
|
|
41
|
+
emptyDescription: "New activity from your workflows will show up here.",
|
|
42
|
+
emptyUnreadTitle: "No unread notifications"
|
|
43
|
+
};
|
|
44
|
+
function h({ notifications: s, onSelect: c, onMarkAllRead: p, footer: h, loading: _ = !1, locale: v, open: y, onOpenChange: b, labels: x, className: S }) {
|
|
45
|
+
let C = {
|
|
46
|
+
...m,
|
|
47
|
+
...x
|
|
48
|
+
}, w = o(a), [T, E] = d(!1), D = y ?? T, O = (e) => {
|
|
49
|
+
y === void 0 && E(e), b?.(e);
|
|
50
|
+
}, k = s.filter((e) => !e.read).length, A = k > 0 ? `${C.title}, ${C.unreadCount.replace("{count}", String(k))}` : C.title, j = /* @__PURE__ */ u("button", {
|
|
51
|
+
type: "button",
|
|
52
|
+
"aria-label": A,
|
|
53
|
+
className: e("relative grid size-11 cursor-pointer place-items-center rounded-full border-0 bg-transparent text-fg", "transition-colors hover:bg-surface-muted focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-focus", S),
|
|
54
|
+
children: [/* @__PURE__ */ l(t, {
|
|
55
|
+
name: "notify",
|
|
56
|
+
size: 26
|
|
57
|
+
}), k > 0 && /* @__PURE__ */ l("span", {
|
|
58
|
+
"aria-hidden": "true",
|
|
59
|
+
className: "absolute top-1 right-0.5 grid h-5 min-w-5 place-items-center rounded-full bg-danger-solid px-1 font-sans text-[11px] leading-none font-bold text-on-danger-solid ring-2 ring-bg",
|
|
60
|
+
children: k > 99 ? "99+" : k
|
|
61
|
+
})]
|
|
62
|
+
}), M = /* @__PURE__ */ l(g, {
|
|
63
|
+
notifications: s,
|
|
64
|
+
unread: k,
|
|
65
|
+
onSelect: c,
|
|
66
|
+
onMarkAllRead: p,
|
|
67
|
+
footer: h,
|
|
68
|
+
loading: _,
|
|
69
|
+
locale: v,
|
|
70
|
+
labels: C,
|
|
71
|
+
showTitle: w
|
|
72
|
+
});
|
|
73
|
+
return w ? /* @__PURE__ */ u(f.Root, {
|
|
74
|
+
open: D,
|
|
75
|
+
onOpenChange: O,
|
|
76
|
+
children: [/* @__PURE__ */ l(f.Trigger, {
|
|
77
|
+
asChild: !0,
|
|
78
|
+
children: j
|
|
79
|
+
}), /* @__PURE__ */ l(f.Portal, { children: /* @__PURE__ */ l(f.Content, {
|
|
80
|
+
align: "end",
|
|
81
|
+
sideOffset: 8,
|
|
82
|
+
collisionPadding: 16,
|
|
83
|
+
"aria-label": C.title,
|
|
84
|
+
className: "kf-popover z-50 flex max-h-[min(36rem,var(--radix-popover-content-available-height))] w-[24rem] flex-col overflow-hidden rounded-lg border border-border bg-surface font-sans text-fg shadow-overlay focus:outline-none",
|
|
85
|
+
children: M
|
|
86
|
+
}) })]
|
|
87
|
+
}) : /* @__PURE__ */ u(n, {
|
|
88
|
+
open: D,
|
|
89
|
+
onOpenChange: O,
|
|
90
|
+
children: [/* @__PURE__ */ l(i, {
|
|
91
|
+
asChild: !0,
|
|
92
|
+
children: j
|
|
93
|
+
}), /* @__PURE__ */ l(r, {
|
|
94
|
+
side: "bottom",
|
|
95
|
+
size: "lg",
|
|
96
|
+
title: C.title,
|
|
97
|
+
bodyClassName: "flex flex-col px-0! pb-0!",
|
|
98
|
+
children: M
|
|
99
|
+
})]
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
function g({ notifications: e, unread: t, onSelect: n, onMarkAllRead: r, footer: i, loading: a, locale: o, labels: f, showTitle: p }) {
|
|
103
|
+
let [m, h] = d("all"), g = m === "unread" ? e.filter((e) => !e.read) : e, v = r && t > 0 && /* @__PURE__ */ l("button", {
|
|
104
|
+
type: "button",
|
|
105
|
+
onClick: r,
|
|
106
|
+
className: "ml-auto cursor-pointer rounded-xs border-0 bg-transparent px-1 font-sans text-[13px] font-semibold whitespace-nowrap text-link hover:underline focus-visible:outline-3 focus-visible:outline-focus",
|
|
107
|
+
children: f.markAllRead
|
|
108
|
+
});
|
|
109
|
+
return /* @__PURE__ */ u("div", {
|
|
110
|
+
className: "flex min-h-0 flex-1 flex-col",
|
|
111
|
+
children: [
|
|
112
|
+
/* @__PURE__ */ u("div", {
|
|
113
|
+
className: "grid gap-2 border-b border-border px-4 pt-3 pb-2.5",
|
|
114
|
+
children: [p && /* @__PURE__ */ u("div", {
|
|
115
|
+
className: "flex items-center justify-between gap-3",
|
|
116
|
+
children: [/* @__PURE__ */ l("h2", {
|
|
117
|
+
className: "m-0 font-display text-base font-bold",
|
|
118
|
+
children: f.title
|
|
119
|
+
}), v]
|
|
120
|
+
}), /* @__PURE__ */ u("div", {
|
|
121
|
+
className: "flex items-center gap-3",
|
|
122
|
+
children: [/* @__PURE__ */ l("div", {
|
|
123
|
+
role: "group",
|
|
124
|
+
"aria-label": f.filter,
|
|
125
|
+
className: "-ml-1 flex gap-1",
|
|
126
|
+
children: ["all", "unread"].map((e) => /* @__PURE__ */ l("button", {
|
|
127
|
+
type: "button",
|
|
128
|
+
"aria-pressed": m === e,
|
|
129
|
+
onClick: () => h(e),
|
|
130
|
+
className: "cursor-pointer rounded-full border-0 bg-transparent px-3 py-1 font-sans text-[13px] font-semibold whitespace-nowrap text-fg-muted hover:text-fg focus-visible:outline-3 focus-visible:outline-focus aria-pressed:bg-surface-muted aria-pressed:text-fg",
|
|
131
|
+
children: e === "all" ? f.all : `${f.unread}${t ? ` (${t})` : ""}`
|
|
132
|
+
}, e))
|
|
133
|
+
}), !p && v]
|
|
134
|
+
})]
|
|
135
|
+
}),
|
|
136
|
+
/* @__PURE__ */ l("div", {
|
|
137
|
+
className: "min-h-0 flex-1 overflow-y-auto overscroll-contain",
|
|
138
|
+
"aria-busy": a || void 0,
|
|
139
|
+
children: a ? /* @__PURE__ */ l("ul", {
|
|
140
|
+
className: "m-0 list-none p-0",
|
|
141
|
+
"aria-hidden": "true",
|
|
142
|
+
children: [
|
|
143
|
+
0,
|
|
144
|
+
1,
|
|
145
|
+
2
|
|
146
|
+
].map((e) => /* @__PURE__ */ u("li", {
|
|
147
|
+
className: "flex gap-3 px-4 py-3.5",
|
|
148
|
+
children: [/* @__PURE__ */ l(s, {
|
|
149
|
+
shape: "circle",
|
|
150
|
+
className: "size-9 shrink-0"
|
|
151
|
+
}), /* @__PURE__ */ l(s, {
|
|
152
|
+
shape: "text",
|
|
153
|
+
lines: 2,
|
|
154
|
+
className: "pt-1"
|
|
155
|
+
})]
|
|
156
|
+
}, e))
|
|
157
|
+
}) : g.length === 0 ? /* @__PURE__ */ l(c, {
|
|
158
|
+
size: "sm",
|
|
159
|
+
mascot: "happy",
|
|
160
|
+
headingLevel: 3,
|
|
161
|
+
title: m === "unread" && e.length ? f.emptyUnreadTitle : f.emptyTitle,
|
|
162
|
+
description: f.emptyDescription
|
|
163
|
+
}) : /* @__PURE__ */ l("ul", {
|
|
164
|
+
className: "m-0 list-none p-0",
|
|
165
|
+
children: g.map((e) => /* @__PURE__ */ l("li", {
|
|
166
|
+
className: "border-b border-border last:border-b-0",
|
|
167
|
+
children: /* @__PURE__ */ l(_, {
|
|
168
|
+
item: e,
|
|
169
|
+
locale: o,
|
|
170
|
+
unreadLabel: f.unread,
|
|
171
|
+
onSelect: n
|
|
172
|
+
})
|
|
173
|
+
}, e.id))
|
|
174
|
+
})
|
|
175
|
+
}),
|
|
176
|
+
i && /* @__PURE__ */ l("div", {
|
|
177
|
+
className: "border-t border-border px-4 py-3 text-sm",
|
|
178
|
+
children: i
|
|
179
|
+
})
|
|
180
|
+
]
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
function _({ item: n, locale: r, unreadLabel: i, onSelect: a }) {
|
|
184
|
+
let o = p[n.variant ?? "neutral"], s = new Date(n.time);
|
|
185
|
+
return /* @__PURE__ */ u("button", {
|
|
186
|
+
type: "button",
|
|
187
|
+
onClick: () => a?.(n),
|
|
188
|
+
className: e("flex w-full cursor-pointer gap-3 border-0 px-4 py-3.5 text-left font-sans text-fg", "hover:bg-surface-muted focus-visible:outline-3 focus-visible:-outline-offset-3 focus-visible:outline-focus", n.read ? "bg-transparent" : "bg-info-surface/40"),
|
|
189
|
+
children: [
|
|
190
|
+
/* @__PURE__ */ l("span", {
|
|
191
|
+
className: e("grid size-9 shrink-0 place-items-center rounded-full", o.className),
|
|
192
|
+
children: /* @__PURE__ */ l(t, {
|
|
193
|
+
name: n.icon ?? o.name,
|
|
194
|
+
size: 20
|
|
195
|
+
})
|
|
196
|
+
}),
|
|
197
|
+
/* @__PURE__ */ u("span", {
|
|
198
|
+
className: "grid min-w-0 flex-1 gap-0.5",
|
|
199
|
+
children: [
|
|
200
|
+
/* @__PURE__ */ u("span", {
|
|
201
|
+
className: e("text-sm leading-snug", n.read ? "font-medium" : "font-semibold"),
|
|
202
|
+
children: [!n.read && /* @__PURE__ */ u("span", {
|
|
203
|
+
className: "sr-only",
|
|
204
|
+
children: [i, ": "]
|
|
205
|
+
}), n.title]
|
|
206
|
+
}),
|
|
207
|
+
n.description && /* @__PURE__ */ l("span", {
|
|
208
|
+
className: "line-clamp-2 text-[13px] text-fg-muted",
|
|
209
|
+
children: n.description
|
|
210
|
+
}),
|
|
211
|
+
/* @__PURE__ */ l("time", {
|
|
212
|
+
dateTime: s.toISOString(),
|
|
213
|
+
className: "text-xs text-fg-muted",
|
|
214
|
+
children: y(s, r)
|
|
215
|
+
})
|
|
216
|
+
]
|
|
217
|
+
}),
|
|
218
|
+
!n.read && /* @__PURE__ */ l("span", {
|
|
219
|
+
"aria-hidden": "true",
|
|
220
|
+
className: "mt-1.5 size-2.5 shrink-0 rounded-full bg-link"
|
|
221
|
+
})
|
|
222
|
+
]
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
var v = [
|
|
226
|
+
["year", 31536e3],
|
|
227
|
+
["month", 2592e3],
|
|
228
|
+
["week", 604800],
|
|
229
|
+
["day", 86400],
|
|
230
|
+
["hour", 3600],
|
|
231
|
+
["minute", 60]
|
|
232
|
+
];
|
|
233
|
+
function y(e, t, n = Date.now()) {
|
|
234
|
+
let r = Math.round((e.getTime() - n) / 1e3), i = new Intl.RelativeTimeFormat(t, {
|
|
235
|
+
numeric: "auto",
|
|
236
|
+
style: "short"
|
|
237
|
+
});
|
|
238
|
+
for (let [e, t] of v) if (Math.abs(r) >= t) return i.format(Math.round(r / t), e);
|
|
239
|
+
return i.format(0, "second");
|
|
240
|
+
}
|
|
241
|
+
//#endregion
|
|
242
|
+
export { h as NotificationCenter, y as formatRelative };
|
|
243
|
+
|
|
244
|
+
//# sourceMappingURL=notification-center.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification-center.js","names":["Popover","ICONS","DEFAULT_LABELS","NotificationCenter","openProp","labelOverrides","labels","desktop","useMediaQuery","DESKTOP_QUERY","uncontrolled","setUncontrolled","useState","open","setOpen","next","onOpenChange","unread","notifications","n","bellLabel","bell","cx","className","Icon","panel","NotificationPanel","Drawer","DrawerTrigger","DrawerContent","filter","setFilter","items","markAll","onMarkAllRead","showTitle","f","loading","Skeleton","i","EmptyState","NotificationRow","footer","variant","item","date","onSelect","unreadLabel","formatRelative","locale","UNITS","seconds","now","rtf","unit","size"],"sources":["../../src/notification-center/notification-center.tsx"],"sourcesContent":["'use client';\n\nimport * as Popover from '@radix-ui/react-popover';\nimport { useState, type ReactNode } from 'react';\nimport { cx } from '../lib/cx';\nimport { DESKTOP_QUERY, useMediaQuery } from '../lib/use-media-query';\nimport { Icon, type IconName } from '../icon/icon';\nimport { Skeleton } from '../skeleton/skeleton';\nimport { EmptyState } from '../empty-state/empty-state';\nimport { Drawer, DrawerContent, DrawerTrigger } from '../drawer/drawer';\n\nexport type NotificationVariant = 'neutral' | 'success' | 'warning' | 'danger' | 'info';\n\nexport interface NotificationItem {\n id: string;\n title: ReactNode;\n description?: ReactNode;\n /** When it happened; shown as relative time (\"5 min ago\"). */\n time: Date | string | number;\n read?: boolean;\n variant?: NotificationVariant;\n /** Overrides the variant icon. */\n icon?: IconName;\n}\n\nconst ICONS: Record<NotificationVariant, { name: IconName; className: string }> = {\n neutral: { name: 'notify', className: 'bg-surface-muted text-fg-muted' },\n success: { name: 'accept', className: 'bg-success-surface text-success-icon' },\n warning: { name: 'warning', className: 'bg-warning-surface text-warning-icon' },\n danger: { name: 'error', className: 'bg-danger-surface text-danger-icon' },\n info: { name: 'info', className: 'bg-info-surface text-info-icon' },\n};\n\nexport interface NotificationCenterProps {\n notifications: NotificationItem[];\n /** Called when the user opens an item. Mark it read here and navigate if needed. */\n onSelect?: (item: NotificationItem) => void;\n onMarkAllRead?: () => void;\n /** Footer content, e.g. a \"View all\" link or notification settings. */\n footer?: ReactNode;\n /** Shows a skeleton list while the first page loads. */\n loading?: boolean;\n /** Locale for relative times (e.g. 'es'). */\n locale?: string;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** Translatable strings. */\n labels?: Partial<typeof DEFAULT_LABELS>;\n className?: string;\n}\n\nconst DEFAULT_LABELS = {\n title: 'Notifications',\n /** `{count}` is replaced by the number of unread items. */\n unreadCount: '{count} unread',\n filter: 'Filter',\n all: 'All',\n unread: 'Unread',\n markAllRead: 'Mark all as read',\n emptyTitle: 'You’re all caught up',\n emptyDescription: 'New activity from your workflows will show up here.',\n emptyUnreadTitle: 'No unread notifications',\n};\n\ntype Labels = typeof DEFAULT_LABELS;\n\n/**\n * Bell button with an unread badge that opens the notification list: a popover on desktop,\n * a bottom drawer on mobile. Data and read state stay in your app (pass `notifications`).\n */\nexport function NotificationCenter({\n notifications,\n onSelect,\n onMarkAllRead,\n footer,\n loading = false,\n locale,\n open: openProp,\n onOpenChange,\n labels: labelOverrides,\n className,\n}: NotificationCenterProps) {\n const labels: Labels = { ...DEFAULT_LABELS, ...labelOverrides };\n const desktop = useMediaQuery(DESKTOP_QUERY);\n const [uncontrolled, setUncontrolled] = useState(false);\n const open = openProp ?? uncontrolled;\n const setOpen = (next: boolean) => {\n if (openProp === undefined) setUncontrolled(next);\n onOpenChange?.(next);\n };\n\n const unread = notifications.filter((n) => !n.read).length;\n const bellLabel = unread > 0 ? `${labels.title}, ${labels.unreadCount.replace('{count}', String(unread))}` : labels.title;\n\n const bell = (\n <button\n type=\"button\"\n aria-label={bellLabel}\n className={cx(\n 'relative grid size-11 cursor-pointer place-items-center rounded-full border-0 bg-transparent text-fg',\n 'transition-colors hover:bg-surface-muted focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-focus',\n className,\n )}\n >\n <Icon name=\"notify\" size={26} />\n {unread > 0 && (\n <span\n aria-hidden=\"true\"\n className=\"absolute top-1 right-0.5 grid h-5 min-w-5 place-items-center rounded-full bg-danger-solid px-1 font-sans text-[11px] leading-none font-bold text-on-danger-solid ring-2 ring-bg\"\n >\n {unread > 99 ? '99+' : unread}\n </span>\n )}\n </button>\n );\n\n const panel = (\n <NotificationPanel\n notifications={notifications}\n unread={unread}\n onSelect={onSelect}\n onMarkAllRead={onMarkAllRead}\n footer={footer}\n loading={loading}\n locale={locale}\n labels={labels}\n showTitle={desktop}\n />\n );\n\n if (!desktop) {\n return (\n <Drawer open={open} onOpenChange={setOpen}>\n <DrawerTrigger asChild>{bell}</DrawerTrigger>\n <DrawerContent side=\"bottom\" size=\"lg\" title={labels.title} bodyClassName=\"flex flex-col px-0! pb-0!\">\n {panel}\n </DrawerContent>\n </Drawer>\n );\n }\n\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <Popover.Trigger asChild>{bell}</Popover.Trigger>\n <Popover.Portal>\n <Popover.Content\n align=\"end\"\n sideOffset={8}\n collisionPadding={16}\n aria-label={labels.title}\n className=\"kf-popover z-50 flex max-h-[min(36rem,var(--radix-popover-content-available-height))] w-[24rem] flex-col overflow-hidden rounded-lg border border-border bg-surface font-sans text-fg shadow-overlay focus:outline-none\"\n >\n {panel}\n </Popover.Content>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n\ninterface PanelProps {\n notifications: NotificationItem[];\n unread: number;\n onSelect?: (item: NotificationItem) => void;\n onMarkAllRead?: () => void;\n footer?: ReactNode;\n loading: boolean;\n locale?: string;\n labels: Labels;\n showTitle: boolean;\n}\n\nfunction NotificationPanel({ notifications, unread, onSelect, onMarkAllRead, footer, loading, locale, labels, showTitle }: PanelProps) {\n const [filter, setFilter] = useState<'all' | 'unread'>('all');\n const items = filter === 'unread' ? notifications.filter((n) => !n.read) : notifications;\n const markAll = onMarkAllRead && unread > 0 && (\n <button\n type=\"button\"\n onClick={onMarkAllRead}\n className=\"ml-auto cursor-pointer rounded-xs border-0 bg-transparent px-1 font-sans text-[13px] font-semibold whitespace-nowrap text-link hover:underline focus-visible:outline-3 focus-visible:outline-focus\"\n >\n {labels.markAllRead}\n </button>\n );\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <div className=\"grid gap-2 border-b border-border px-4 pt-3 pb-2.5\">\n {showTitle && (\n <div className=\"flex items-center justify-between gap-3\">\n <h2 className=\"m-0 font-display text-base font-bold\">{labels.title}</h2>\n {markAll}\n </div>\n )}\n <div className=\"flex items-center gap-3\">\n <div role=\"group\" aria-label={labels.filter} className=\"-ml-1 flex gap-1\">\n {(['all', 'unread'] as const).map((f) => (\n <button\n key={f}\n type=\"button\"\n aria-pressed={filter === f}\n onClick={() => setFilter(f)}\n className=\"cursor-pointer rounded-full border-0 bg-transparent px-3 py-1 font-sans text-[13px] font-semibold whitespace-nowrap text-fg-muted hover:text-fg focus-visible:outline-3 focus-visible:outline-focus aria-pressed:bg-surface-muted aria-pressed:text-fg\"\n >\n {f === 'all' ? labels.all : `${labels.unread}${unread ? ` (${unread})` : ''}`}\n </button>\n ))}\n </div>\n {!showTitle && markAll}\n </div>\n </div>\n\n <div className=\"min-h-0 flex-1 overflow-y-auto overscroll-contain\" aria-busy={loading || undefined}>\n {loading ? (\n <ul className=\"m-0 list-none p-0\" aria-hidden=\"true\">\n {[0, 1, 2].map((i) => (\n <li key={i} className=\"flex gap-3 px-4 py-3.5\">\n <Skeleton shape=\"circle\" className=\"size-9 shrink-0\" />\n <Skeleton shape=\"text\" lines={2} className=\"pt-1\" />\n </li>\n ))}\n </ul>\n ) : items.length === 0 ? (\n <EmptyState\n size=\"sm\"\n mascot=\"happy\"\n headingLevel={3}\n title={filter === 'unread' && notifications.length ? labels.emptyUnreadTitle : labels.emptyTitle}\n description={labels.emptyDescription}\n />\n ) : (\n <ul className=\"m-0 list-none p-0\">\n {items.map((n) => (\n <li key={n.id} className=\"border-b border-border last:border-b-0\">\n <NotificationRow item={n} locale={locale} unreadLabel={labels.unread} onSelect={onSelect} />\n </li>\n ))}\n </ul>\n )}\n </div>\n\n {footer && <div className=\"border-t border-border px-4 py-3 text-sm\">{footer}</div>}\n </div>\n );\n}\n\nfunction NotificationRow({\n item,\n locale,\n unreadLabel,\n onSelect,\n}: {\n item: NotificationItem;\n locale?: string;\n unreadLabel: string;\n onSelect?: (item: NotificationItem) => void;\n}) {\n const variant = ICONS[item.variant ?? 'neutral'];\n const date = new Date(item.time);\n return (\n <button\n type=\"button\"\n onClick={() => onSelect?.(item)}\n className={cx(\n 'flex w-full cursor-pointer gap-3 border-0 px-4 py-3.5 text-left font-sans text-fg',\n 'hover:bg-surface-muted focus-visible:outline-3 focus-visible:-outline-offset-3 focus-visible:outline-focus',\n item.read ? 'bg-transparent' : 'bg-info-surface/40',\n )}\n >\n <span className={cx('grid size-9 shrink-0 place-items-center rounded-full', variant.className)}>\n <Icon name={item.icon ?? variant.name} size={20} />\n </span>\n <span className=\"grid min-w-0 flex-1 gap-0.5\">\n <span className={cx('text-sm leading-snug', item.read ? 'font-medium' : 'font-semibold')}>\n {!item.read && <span className=\"sr-only\">{unreadLabel}: </span>}\n {item.title}\n </span>\n {item.description && <span className=\"line-clamp-2 text-[13px] text-fg-muted\">{item.description}</span>}\n <time dateTime={date.toISOString()} className=\"text-xs text-fg-muted\">\n {formatRelative(date, locale)}\n </time>\n </span>\n {!item.read && <span aria-hidden=\"true\" className=\"mt-1.5 size-2.5 shrink-0 rounded-full bg-link\" />}\n </button>\n );\n}\n\nconst UNITS: [Intl.RelativeTimeFormatUnit, number][] = [\n ['year', 31_536_000],\n ['month', 2_592_000],\n ['week', 604_800],\n ['day', 86_400],\n ['hour', 3_600],\n ['minute', 60],\n];\n\n/** \"5 minutes ago\", \"yesterday\", \"just now\" — in the given locale. */\nexport function formatRelative(date: Date, locale?: string, now = Date.now()) {\n const seconds = Math.round((date.getTime() - now) / 1000);\n const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto', style: 'short' });\n for (const [unit, size] of UNITS) {\n if (Math.abs(seconds) >= size) return rtf.format(Math.round(seconds / size), unit);\n }\n return rtf.format(0, 'second');\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface OtpInputProps {
|
|
2
|
+
value: string;
|
|
3
|
+
onChange: (value: string) => void;
|
|
4
|
+
/** Called once all digits are filled (e.g. submit automatically). */
|
|
5
|
+
onComplete?: (value: string) => void;
|
|
6
|
+
length?: number;
|
|
7
|
+
/** Allow letters as well as digits. */
|
|
8
|
+
alphanumeric?: boolean;
|
|
9
|
+
id?: string;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
invalid?: boolean;
|
|
12
|
+
/** Accessible name pattern for each box; `{n}` and `{count}` are replaced. */
|
|
13
|
+
digitLabel?: string;
|
|
14
|
+
/** Visual gap after this many boxes (e.g. 3 → "123 456"). */
|
|
15
|
+
groupSize?: number;
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* One-time code entry (2FA, email verification). Typing advances, Backspace goes back,
|
|
20
|
+
* pasting a full code fills every box, and `autocomplete="one-time-code"` lets phones suggest
|
|
21
|
+
* the code from SMS.
|
|
22
|
+
*/
|
|
23
|
+
export declare function OtpInput({ value, onChange, onComplete, length, alphanumeric, digitLabel, groupSize, className, ...rest }: OtpInputProps): import("react").JSX.Element;
|