@fanvue/ui 3.5.0 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/charts.d.ts +1 -1
- package/dist/cjs/components/Chart/ChartCard.cjs +2 -2
- package/dist/cjs/components/Chart/ChartCard.cjs.map +1 -1
- package/dist/cjs/components/ChatInput/ChatInput.cjs +128 -92
- package/dist/cjs/components/ChatInput/ChatInput.cjs.map +1 -1
- package/dist/cjs/components/Chip/Chip.cjs +46 -10
- package/dist/cjs/components/Chip/Chip.cjs.map +1 -1
- package/dist/cjs/components/Drawer/Drawer.cjs +6 -3
- package/dist/cjs/components/Drawer/Drawer.cjs.map +1 -1
- package/dist/cjs/components/DropdownMenu/DropdownMenu.cjs +20 -4
- package/dist/cjs/components/DropdownMenu/DropdownMenu.cjs.map +1 -1
- package/dist/cjs/components/Icons/TickIcon.cjs +3 -1
- package/dist/cjs/components/Icons/TickIcon.cjs.map +1 -1
- package/dist/cjs/components/Logo/Logo.cjs +107 -33
- package/dist/cjs/components/Logo/Logo.cjs.map +1 -1
- package/dist/cjs/components/Logo/agenciesIcon.cjs +6 -0
- package/dist/cjs/components/Logo/agenciesIcon.cjs.map +1 -0
- package/dist/cjs/components/Tabs/TabsList.cjs +20 -12
- package/dist/cjs/components/Tabs/TabsList.cjs.map +1 -1
- package/dist/cjs/components/Tabs/TabsTrigger.cjs +8 -7
- package/dist/cjs/components/Tabs/TabsTrigger.cjs.map +1 -1
- package/dist/components/Chart/ChartCard.mjs +2 -2
- package/dist/components/Chart/ChartCard.mjs.map +1 -1
- package/dist/components/ChatInput/ChatInput.mjs +128 -92
- package/dist/components/ChatInput/ChatInput.mjs.map +1 -1
- package/dist/components/Chip/Chip.mjs +46 -10
- package/dist/components/Chip/Chip.mjs.map +1 -1
- package/dist/components/Drawer/Drawer.mjs +6 -3
- package/dist/components/Drawer/Drawer.mjs.map +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.mjs +20 -4
- package/dist/components/DropdownMenu/DropdownMenu.mjs.map +1 -1
- package/dist/components/Icons/TickIcon.mjs +3 -1
- package/dist/components/Icons/TickIcon.mjs.map +1 -1
- package/dist/components/Logo/Logo.mjs +107 -33
- package/dist/components/Logo/Logo.mjs.map +1 -1
- package/dist/components/Logo/agenciesIcon.mjs +6 -0
- package/dist/components/Logo/agenciesIcon.mjs.map +1 -0
- package/dist/components/Tabs/TabsList.mjs +20 -12
- package/dist/components/Tabs/TabsList.mjs.map +1 -1
- package/dist/components/Tabs/TabsTrigger.mjs +8 -7
- package/dist/components/Tabs/TabsTrigger.mjs.map +1 -1
- package/dist/index.d.ts +61 -6
- package/package.json +8 -4
|
@@ -26,6 +26,7 @@ function _interopNamespaceDefault(e) {
|
|
|
26
26
|
}
|
|
27
27
|
const DialogPrimitive__namespace = /* @__PURE__ */ _interopNamespaceDefault(DialogPrimitive);
|
|
28
28
|
const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
|
|
29
|
+
const SHEET_CLASSES = "rounded-t-xl border border-modal-stroke bg-modal-background shadow-blur-menu backdrop-blur-[4px]";
|
|
29
30
|
const DrawerContext = React__namespace.createContext({
|
|
30
31
|
overlay: true
|
|
31
32
|
});
|
|
@@ -65,6 +66,7 @@ const DrawerContent = React__namespace.forwardRef(
|
|
|
65
66
|
className,
|
|
66
67
|
position = "right",
|
|
67
68
|
size = "sm",
|
|
69
|
+
variant = "panel",
|
|
68
70
|
overlay: overlayProp,
|
|
69
71
|
overlayProps,
|
|
70
72
|
style,
|
|
@@ -102,6 +104,7 @@ const DrawerContent = React__namespace.forwardRef(
|
|
|
102
104
|
"data-[state=open]:duration-200 data-[state=open]:ease-out",
|
|
103
105
|
SLIDE_CLASSES[position],
|
|
104
106
|
sizeClass,
|
|
107
|
+
variant === "sheet" && SHEET_CLASSES,
|
|
105
108
|
className
|
|
106
109
|
),
|
|
107
110
|
...props,
|
|
@@ -113,15 +116,15 @@ const DrawerContent = React__namespace.forwardRef(
|
|
|
113
116
|
);
|
|
114
117
|
DrawerContent.displayName = "DrawerContent";
|
|
115
118
|
const DrawerHeader = React__namespace.forwardRef(
|
|
116
|
-
({ className, showClose = true, closeLabel = "Close drawer", children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn.cn("flex items-
|
|
119
|
+
({ className, showClose = true, closeLabel = "Close drawer", children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn.cn("flex items-center gap-2 p-4", className), ...props, children: [
|
|
117
120
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children }),
|
|
118
121
|
showClose && /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
119
122
|
IconButton.IconButton,
|
|
120
123
|
{
|
|
121
124
|
icon: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon.CloseIcon, {}),
|
|
122
125
|
"aria-label": closeLabel,
|
|
123
|
-
variant: "
|
|
124
|
-
size: "
|
|
126
|
+
variant: "secondary",
|
|
127
|
+
size: "32",
|
|
125
128
|
className: "shrink-0"
|
|
126
129
|
}
|
|
127
130
|
) })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Drawer.cjs","sources":["../../../../src/components/Drawer/Drawer.tsx"],"sourcesContent":["import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useSuppressClickAfterDrag } from \"../../utils/useSuppressClickAfterDrag\";\nimport { IconButton } from \"../IconButton/IconButton\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\n\n/** The side from which the drawer slides in. */\nexport type DrawerPosition = \"left\" | \"right\" | \"top\" | \"bottom\";\n\n/** Size presets for the drawer panel. Maps to max-width (left/right) or max-height (top/bottom). */\nexport type DrawerSize = \"sm\" | \"md\" | \"lg\" | \"full\";\n\n/**\n * Props for the {@link Drawer} root component.\n *\n * Inherits `open`, `onOpenChange`, and `defaultOpen` from Radix Dialog.Root.\n *\n * The Radix `modal` prop (default `true`) can also be passed to create a\n * non-modal drawer — useful for persistent side navigation that does not\n * block interaction with the rest of the page.\n *\n * **`overlay` behaviour:** When `overlay` is `false`, the component\n * automatically sets `modal={false}` on the underlying Radix Dialog.Root.\n * A modal dialog without a visible overlay is confusing because focus is\n * still trapped and scroll is blocked even though the page appears\n * interactive. Passing `modal={true}` explicitly will override this.\n */\nexport interface DrawerProps extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Root> {\n /**\n * Whether the default {@link DrawerOverlay} is rendered.\n * When `false`, `modal` is automatically set to `false` as well\n * (unless explicitly overridden) so focus-trap and scroll-lock are disabled.\n * @default true\n */\n overlay?: boolean;\n}\n\nconst DrawerContext = React.createContext<{ overlay: boolean }>({\n overlay: true,\n});\n\n/**\n * Root component that manages open/close state for a drawer.\n * Wraps Radix Dialog.Root.\n *\n * @example\n * ```tsx\n * <Drawer>\n * <DrawerTrigger>Open</DrawerTrigger>\n * <DrawerContent position=\"right\">\n * <DrawerHeader>\n * <DrawerTitle>Settings</DrawerTitle>\n * <DrawerDescription>Adjust your preferences.</DrawerDescription>\n * </DrawerHeader>\n * <p>Content goes here.</p>\n * <DrawerFooter>\n * <DrawerClose>Done</DrawerClose>\n * </DrawerFooter>\n * </DrawerContent>\n * </Drawer>\n * ```\n */\nexport function Drawer({ overlay = true, modal, children, ...props }: DrawerProps) {\n const resolvedModal = modal ?? (overlay ? undefined : false);\n return (\n <DrawerContext.Provider value={{ overlay }}>\n <DialogPrimitive.Root modal={resolvedModal} {...props}>\n {children}\n </DialogPrimitive.Root>\n </DrawerContext.Provider>\n );\n}\nDrawer.displayName = \"Drawer\";\n\n/** Props for the {@link DrawerTrigger} component. */\nexport type DrawerTriggerProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Trigger>;\n\n/**\n * The element that opens the drawer when clicked.\n *\n * On touch / pen, a press-and-release that crosses a small movement threshold\n * is treated as a drag and the resulting synthetic click is suppressed —\n * defends against Android Chrome opening the drawer on a scroll-drag-end.\n */\nexport const DrawerTrigger = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Trigger>,\n DrawerTriggerProps\n>((props, ref) => <DialogPrimitive.Trigger ref={ref} {...useSuppressClickAfterDrag(props)} />);\nDrawerTrigger.displayName = \"DrawerTrigger\";\n\n/** Props for the {@link DrawerClose} component. */\nexport type DrawerCloseProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Close>;\n\n/** Closes the drawer when clicked. Can be placed anywhere inside the drawer. */\nexport const DrawerClose = DialogPrimitive.Close;\nDrawerClose.displayName = \"DrawerClose\";\n\n/** Props for the {@link DrawerOverlay} component. */\nexport interface DrawerOverlayProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> {}\n\n/**\n * A translucent backdrop rendered behind the drawer content.\n * Clicking the overlay closes the drawer by default.\n */\nexport const DrawerOverlay = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Overlay>,\n DrawerOverlayProps\n>(({ className, style, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n className={cn(\n \"fixed inset-0 bg-background-overlay-default\",\n \"data-[state=closed]:animate-out data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:duration-150 data-[state=closed]:ease-in\",\n \"data-[state=open]:fade-in-0 data-[state=open]:duration-200 data-[state=open]:ease-out\",\n className,\n )}\n {...props}\n />\n));\nDrawerOverlay.displayName = \"DrawerOverlay\";\n\n/**\n * Slide-in animation classes keyed by position.\n * Uses Tailwind animate utilities (animate-in / animate-out).\n */\nconst SLIDE_CLASSES: Record<DrawerPosition, string> = {\n right:\n \"inset-y-0 right-0 h-full w-2/3 data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right\",\n left: \"inset-y-0 left-0 h-full w-2/3 data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left\",\n top: \"inset-x-0 top-0 w-full data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top\",\n bottom:\n \"inset-x-0 bottom-0 w-full rounded-t-xs data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom\",\n};\n\n/** Props for the {@link DrawerContent} component. */\nexport interface DrawerContentProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {\n /**\n * The edge from which the drawer slides in.\n *\n * Named `position` (rather than `side`) to avoid confusion with the CSS\n * `side` concept used by Radix Popover/Tooltip and to better convey the\n * spatial relationship of the drawer to the viewport.\n *\n * @default \"right\"\n */\n position?: DrawerPosition;\n /**\n * Controls the maximum extent of the drawer panel.\n * For left/right drawers this sets `max-width`; for top/bottom it sets `max-height`.\n * @default \"sm\"\n */\n size?: DrawerSize;\n /**\n * Whether to render the default {@link DrawerOverlay} behind the content.\n * Set to `false` to provide your own overlay or omit it entirely.\n *\n * Prefer setting `overlay` on the {@link Drawer} root instead so that\n * `modal` is also adjusted automatically.\n *\n * @default true\n */\n overlay?: boolean;\n /** Props forwarded to the default {@link DrawerOverlay} when `overlay` is `true`. */\n overlayProps?: DrawerOverlayProps;\n}\n\n/**\n * The panel that slides in from the chosen edge. Renders inside a portal with\n * an overlay backdrop by default.\n *\n * Includes focus-trap, `aria-describedby`, and Escape-to-close from Radix Dialog.\n */\nexport const DrawerContent = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Content>,\n DrawerContentProps\n>(\n (\n {\n className,\n position = \"right\",\n size = \"sm\",\n overlay: overlayProp,\n overlayProps,\n style,\n children,\n ...props\n },\n ref,\n ) => {\n const ctx = React.useContext(DrawerContext);\n const overlay = overlayProp ?? ctx.overlay;\n const isHorizontal = position === \"left\" || position === \"right\";\n const sizeClass = isHorizontal\n ? (\n {\n sm: \"max-w-sm\",\n md: \"max-w-md\",\n lg: \"max-w-lg\",\n full: \"max-w-full\",\n } as const\n )[size]\n : (\n {\n sm: \"max-h-[24rem]\",\n md: \"max-h-[28rem]\",\n lg: \"max-h-[32rem]\",\n full: \"max-h-full\",\n } as const\n )[size];\n\n return (\n <DialogPrimitive.Portal>\n {overlay && <DrawerOverlay {...overlayProps} />}\n <DialogPrimitive.Content\n ref={ref}\n style={{\n zIndex: \"calc(var(--fanvue-ui-portal-z-index, 50) + 1)\",\n ...style,\n }}\n className={cn(\n \"fixed flex flex-col bg-surface-secondary shadow-lg outline-none backdrop-blur-lg\",\n \"data-[state=closed]:animate-out data-[state=open]:animate-in\",\n \"data-[state=closed]:duration-150 data-[state=closed]:ease-in\",\n \"data-[state=open]:duration-200 data-[state=open]:ease-out\",\n SLIDE_CLASSES[position],\n sizeClass,\n className,\n )}\n {...props}\n >\n {children}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n );\n },\n);\nDrawerContent.displayName = \"DrawerContent\";\n\n/** Props for the {@link DrawerHeader} component. */\nexport interface DrawerHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Whether to show a built-in close (X) button. @default true */\n showClose?: boolean;\n /** Accessible label for the close button. @default \"Close drawer\" */\n closeLabel?: string;\n}\n\n/**\n * A semantic header area for the drawer, typically containing a title and description.\n * Renders a built-in close button by default.\n */\nexport const DrawerHeader = React.forwardRef<HTMLDivElement, DrawerHeaderProps>(\n ({ className, showClose = true, closeLabel = \"Close drawer\", children, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex items-start gap-2 p-4\", className)} {...props}>\n <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">{children}</div>\n {showClose && (\n <DialogPrimitive.Close asChild>\n <IconButton\n icon={<CloseIcon />}\n aria-label={closeLabel}\n variant=\"tertiary\"\n size=\"24\"\n className=\"shrink-0\"\n />\n </DialogPrimitive.Close>\n )}\n </div>\n ),\n);\nDrawerHeader.displayName = \"DrawerHeader\";\n\n/** Props for the {@link DrawerFooter} component. */\nexport interface DrawerFooterProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/** A semantic footer area for the drawer, typically containing action buttons. */\nexport const DrawerFooter = React.forwardRef<HTMLDivElement, DrawerFooterProps>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex flex-col gap-2 p-4\", className)} {...props} />\n ),\n);\nDrawerFooter.displayName = \"DrawerFooter\";\n\n/** Props for the {@link DrawerTitle} component. */\nexport interface DrawerTitleProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title> {}\n\n/** An accessible title for the drawer. Required for screen readers. */\nexport const DrawerTitle = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Title>,\n DrawerTitleProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\"typography-body-default-16px-semibold truncate text-content-primary\", className)}\n {...props}\n />\n));\nDrawerTitle.displayName = \"DrawerTitle\";\n\n/** Props for the {@link DrawerDescription} component. */\nexport interface DrawerDescriptionProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description> {}\n\n/** An accessible description for the drawer, providing supplementary context. */\nexport const DrawerDescription = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Description>,\n DrawerDescriptionProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"typography-body-small-14px-regular text-content-secondary\", className)}\n {...props}\n />\n));\nDrawerDescription.displayName = \"DrawerDescription\";\n"],"names":["React","jsx","DialogPrimitive","useSuppressClickAfterDrag","cn","jsxs","IconButton","CloseIcon"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA,MAAM,gBAAgBA,iBAAM,cAAoC;AAAA,EAC9D,SAAS;AACX,CAAC;AAuBM,SAAS,OAAO,EAAE,UAAU,MAAM,OAAO,UAAU,GAAG,SAAsB;AACjF,QAAM,gBAAgB,UAAU,UAAU,SAAY;AACtD,wCACG,cAAc,UAAd,EAAuB,OAAO,EAAE,QAAA,GAC/B,UAAAC,2BAAAA,IAACC,2BAAgB,MAAhB,EAAqB,OAAO,eAAgB,GAAG,OAC7C,UACH,GACF;AAEJ;AACA,OAAO,cAAc;AAYd,MAAM,gBAAgBF,iBAAM,WAGjC,CAAC,OAAO,QAAQC,2BAAAA,IAACC,2BAAgB,SAAhB,EAAwB,KAAW,GAAGC,0BAAAA,0BAA0B,KAAK,GAAG,CAAE;AAC7F,cAAc,cAAc;AAMrB,MAAM,cAAcD,2BAAgB;AAC3C,YAAY,cAAc;AAUnB,MAAM,gBAAgBF,iBAAM,WAGjC,CAAC,EAAE,WAAW,OAAO,GAAG,SAAS,QACjCC,2BAAAA;AAAAA,EAACC,2BAAgB;AAAA,EAAhB;AAAA,IACC;AAAA,IACA,OAAO,EAAE,QAAQ,uCAAuC,GAAG,MAAA;AAAA,IAC3D,WAAWE,GAAAA;AAAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,IAED,GAAG;AAAA,EAAA;AACN,CACD;AACD,cAAc,cAAc;AAM5B,MAAM,gBAAgD;AAAA,EACpD,OACE;AAAA,EACF,MAAM;AAAA,EACN,KAAK;AAAA,EACL,QACE;AACJ;AAyCO,MAAM,gBAAgBJ,iBAAM;AAAA,EAIjC,CACE;AAAA,IACE;AAAA,IACA,WAAW;AAAA,IACX,OAAO;AAAA,IACP,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,MAAMA,iBAAM,WAAW,aAAa;AAC1C,UAAM,UAAU,eAAe,IAAI;AACnC,UAAM,eAAe,aAAa,UAAU,aAAa;AACzD,UAAM,YAAY,eAEZ;AAAA,MACE,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,MAAM;AAAA,IAAA,EAER,IAAI,IAEJ;AAAA,MACE,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,MAAM;AAAA,IAAA,EAER,IAAI;AAEV,WACEK,gCAACH,2BAAgB,QAAhB,EACE,UAAA;AAAA,MAAA,WAAWD,2BAAAA,IAAC,eAAA,EAAe,GAAG,aAAA,CAAc;AAAA,MAC7CA,2BAAAA;AAAAA,QAACC,2BAAgB;AAAA,QAAhB;AAAA,UACC;AAAA,UACA,OAAO;AAAA,YACL,QAAQ;AAAA,YACR,GAAG;AAAA,UAAA;AAAA,UAEL,WAAWE,GAAAA;AAAAA,YACT;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,cAAc,QAAQ;AAAA,YACtB;AAAA,YACA;AAAA,UAAA;AAAA,UAED,GAAG;AAAA,UAEH;AAAA,QAAA;AAAA,MAAA;AAAA,IACH,GACF;AAAA,EAEJ;AACF;AACA,cAAc,cAAc;AAcrB,MAAM,eAAeJ,iBAAM;AAAA,EAChC,CAAC,EAAE,WAAW,YAAY,MAAM,aAAa,gBAAgB,UAAU,GAAG,MAAA,GAAS,QACjFK,2BAAAA,KAAC,SAAI,KAAU,WAAWD,GAAAA,GAAG,8BAA8B,SAAS,GAAI,GAAG,OACzE,UAAA;AAAA,IAAAH,2BAAAA,IAAC,OAAA,EAAI,WAAU,wCAAwC,SAAA,CAAS;AAAA,IAC/D,aACCA,2BAAAA,IAACC,2BAAgB,OAAhB,EAAsB,SAAO,MAC5B,UAAAD,2BAAAA;AAAAA,MAACK,WAAAA;AAAAA,MAAA;AAAA,QACC,qCAAOC,UAAAA,WAAA,EAAU;AAAA,QACjB,cAAY;AAAA,QACZ,SAAQ;AAAA,QACR,MAAK;AAAA,QACL,WAAU;AAAA,MAAA;AAAA,IAAA,EACZ,CACF;AAAA,EAAA,EAAA,CAEJ;AAEJ;AACA,aAAa,cAAc;AAMpB,MAAM,eAAeP,iBAAM;AAAA,EAChC,CAAC,EAAE,WAAW,GAAG,MAAA,GAAS,QACxBC,2BAAAA,IAAC,OAAA,EAAI,KAAU,WAAWG,GAAAA,GAAG,2BAA2B,SAAS,GAAI,GAAG,MAAA,CAAO;AAEnF;AACA,aAAa,cAAc;AAOpB,MAAM,cAAcJ,iBAAM,WAG/B,CAAC,EAAE,WAAW,GAAG,MAAA,GAAS,QAC1BC,2BAAAA;AAAAA,EAACC,2BAAgB;AAAA,EAAhB;AAAA,IACC;AAAA,IACA,WAAWE,GAAAA,GAAG,uEAAuE,SAAS;AAAA,IAC7F,GAAG;AAAA,EAAA;AACN,CACD;AACD,YAAY,cAAc;AAOnB,MAAM,oBAAoBJ,iBAAM,WAGrC,CAAC,EAAE,WAAW,GAAG,MAAA,GAAS,QAC1BC,2BAAAA;AAAAA,EAACC,2BAAgB;AAAA,EAAhB;AAAA,IACC;AAAA,IACA,WAAWE,GAAAA,GAAG,6DAA6D,SAAS;AAAA,IACnF,GAAG;AAAA,EAAA;AACN,CACD;AACD,kBAAkB,cAAc;;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"Drawer.cjs","sources":["../../../../src/components/Drawer/Drawer.tsx"],"sourcesContent":["import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useSuppressClickAfterDrag } from \"../../utils/useSuppressClickAfterDrag\";\nimport { IconButton } from \"../IconButton/IconButton\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\n\n/** The side from which the drawer slides in. */\nexport type DrawerPosition = \"left\" | \"right\" | \"top\" | \"bottom\";\n\n/** Size presets for the drawer panel. Maps to max-width (left/right) or max-height (top/bottom). */\nexport type DrawerSize = \"sm\" | \"md\" | \"lg\" | \"full\";\n\n/**\n * Visual treatment of the drawer panel.\n *\n * - `\"panel\"` (default) — the standard edge-anchored surface.\n * - `\"sheet\"` — a bottom-sheet treatment matching the modal surface: large\n * top-only radius (32px), modal background/stroke, and menu blur+shadow.\n * Intended for `position=\"bottom\"`.\n */\nexport type DrawerVariant = \"panel\" | \"sheet\";\n\n/**\n * Shared surface classes for the `\"sheet\"` variant. Mirrors the mobile sheet\n * treatment used by {@link Dialog} so bottom sheets are visually consistent.\n */\nconst SHEET_CLASSES =\n \"rounded-t-xl border border-modal-stroke bg-modal-background shadow-blur-menu backdrop-blur-[4px]\";\n\n/**\n * Props for the {@link Drawer} root component.\n *\n * Inherits `open`, `onOpenChange`, and `defaultOpen` from Radix Dialog.Root.\n *\n * The Radix `modal` prop (default `true`) can also be passed to create a\n * non-modal drawer — useful for persistent side navigation that does not\n * block interaction with the rest of the page.\n *\n * **`overlay` behaviour:** When `overlay` is `false`, the component\n * automatically sets `modal={false}` on the underlying Radix Dialog.Root.\n * A modal dialog without a visible overlay is confusing because focus is\n * still trapped and scroll is blocked even though the page appears\n * interactive. Passing `modal={true}` explicitly will override this.\n */\nexport interface DrawerProps extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Root> {\n /**\n * Whether the default {@link DrawerOverlay} is rendered.\n * When `false`, `modal` is automatically set to `false` as well\n * (unless explicitly overridden) so focus-trap and scroll-lock are disabled.\n * @default true\n */\n overlay?: boolean;\n}\n\nconst DrawerContext = React.createContext<{ overlay: boolean }>({\n overlay: true,\n});\n\n/**\n * Root component that manages open/close state for a drawer.\n * Wraps Radix Dialog.Root.\n *\n * @example\n * ```tsx\n * <Drawer>\n * <DrawerTrigger>Open</DrawerTrigger>\n * <DrawerContent position=\"right\">\n * <DrawerHeader>\n * <DrawerTitle>Settings</DrawerTitle>\n * <DrawerDescription>Adjust your preferences.</DrawerDescription>\n * </DrawerHeader>\n * <p>Content goes here.</p>\n * <DrawerFooter>\n * <DrawerClose>Done</DrawerClose>\n * </DrawerFooter>\n * </DrawerContent>\n * </Drawer>\n * ```\n */\nexport function Drawer({ overlay = true, modal, children, ...props }: DrawerProps) {\n const resolvedModal = modal ?? (overlay ? undefined : false);\n return (\n <DrawerContext.Provider value={{ overlay }}>\n <DialogPrimitive.Root modal={resolvedModal} {...props}>\n {children}\n </DialogPrimitive.Root>\n </DrawerContext.Provider>\n );\n}\nDrawer.displayName = \"Drawer\";\n\n/** Props for the {@link DrawerTrigger} component. */\nexport type DrawerTriggerProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Trigger>;\n\n/**\n * The element that opens the drawer when clicked.\n *\n * On touch / pen, a press-and-release that crosses a small movement threshold\n * is treated as a drag and the resulting synthetic click is suppressed —\n * defends against Android Chrome opening the drawer on a scroll-drag-end.\n */\nexport const DrawerTrigger = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Trigger>,\n DrawerTriggerProps\n>((props, ref) => <DialogPrimitive.Trigger ref={ref} {...useSuppressClickAfterDrag(props)} />);\nDrawerTrigger.displayName = \"DrawerTrigger\";\n\n/** Props for the {@link DrawerClose} component. */\nexport type DrawerCloseProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Close>;\n\n/** Closes the drawer when clicked. Can be placed anywhere inside the drawer. */\nexport const DrawerClose = DialogPrimitive.Close;\nDrawerClose.displayName = \"DrawerClose\";\n\n/** Props for the {@link DrawerOverlay} component. */\nexport interface DrawerOverlayProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> {}\n\n/**\n * A translucent backdrop rendered behind the drawer content.\n * Clicking the overlay closes the drawer by default.\n */\nexport const DrawerOverlay = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Overlay>,\n DrawerOverlayProps\n>(({ className, style, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n className={cn(\n \"fixed inset-0 bg-background-overlay-default\",\n \"data-[state=closed]:animate-out data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:duration-150 data-[state=closed]:ease-in\",\n \"data-[state=open]:fade-in-0 data-[state=open]:duration-200 data-[state=open]:ease-out\",\n className,\n )}\n {...props}\n />\n));\nDrawerOverlay.displayName = \"DrawerOverlay\";\n\n/**\n * Slide-in animation classes keyed by position.\n * Uses Tailwind animate utilities (animate-in / animate-out).\n */\nconst SLIDE_CLASSES: Record<DrawerPosition, string> = {\n right:\n \"inset-y-0 right-0 h-full w-2/3 data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right\",\n left: \"inset-y-0 left-0 h-full w-2/3 data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left\",\n top: \"inset-x-0 top-0 w-full data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top\",\n bottom:\n \"inset-x-0 bottom-0 w-full rounded-t-xs data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom\",\n};\n\n/** Props for the {@link DrawerContent} component. */\nexport interface DrawerContentProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {\n /**\n * The edge from which the drawer slides in.\n *\n * Named `position` (rather than `side`) to avoid confusion with the CSS\n * `side` concept used by Radix Popover/Tooltip and to better convey the\n * spatial relationship of the drawer to the viewport.\n *\n * @default \"right\"\n */\n position?: DrawerPosition;\n /**\n * Controls the maximum extent of the drawer panel.\n * For left/right drawers this sets `max-width`; for top/bottom it sets `max-height`.\n * @default \"sm\"\n */\n size?: DrawerSize;\n /**\n * Visual treatment of the panel. Use `\"sheet\"` (with `position=\"bottom\"`) for\n * a bottom sheet with the modal surface treatment. @default \"panel\"\n */\n variant?: DrawerVariant;\n /**\n * Whether to render the default {@link DrawerOverlay} behind the content.\n * Set to `false` to provide your own overlay or omit it entirely.\n *\n * Prefer setting `overlay` on the {@link Drawer} root instead so that\n * `modal` is also adjusted automatically.\n *\n * @default true\n */\n overlay?: boolean;\n /** Props forwarded to the default {@link DrawerOverlay} when `overlay` is `true`. */\n overlayProps?: DrawerOverlayProps;\n}\n\n/**\n * The panel that slides in from the chosen edge. Renders inside a portal with\n * an overlay backdrop by default.\n *\n * Includes focus-trap, `aria-describedby`, and Escape-to-close from Radix Dialog.\n */\nexport const DrawerContent = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Content>,\n DrawerContentProps\n>(\n (\n {\n className,\n position = \"right\",\n size = \"sm\",\n variant = \"panel\",\n overlay: overlayProp,\n overlayProps,\n style,\n children,\n ...props\n },\n ref,\n ) => {\n const ctx = React.useContext(DrawerContext);\n const overlay = overlayProp ?? ctx.overlay;\n const isHorizontal = position === \"left\" || position === \"right\";\n const sizeClass = isHorizontal\n ? (\n {\n sm: \"max-w-sm\",\n md: \"max-w-md\",\n lg: \"max-w-lg\",\n full: \"max-w-full\",\n } as const\n )[size]\n : (\n {\n sm: \"max-h-[24rem]\",\n md: \"max-h-[28rem]\",\n lg: \"max-h-[32rem]\",\n full: \"max-h-full\",\n } as const\n )[size];\n\n return (\n <DialogPrimitive.Portal>\n {overlay && <DrawerOverlay {...overlayProps} />}\n <DialogPrimitive.Content\n ref={ref}\n style={{\n zIndex: \"calc(var(--fanvue-ui-portal-z-index, 50) + 1)\",\n ...style,\n }}\n className={cn(\n \"fixed flex flex-col bg-surface-secondary shadow-lg outline-none backdrop-blur-lg\",\n \"data-[state=closed]:animate-out data-[state=open]:animate-in\",\n \"data-[state=closed]:duration-150 data-[state=closed]:ease-in\",\n \"data-[state=open]:duration-200 data-[state=open]:ease-out\",\n SLIDE_CLASSES[position],\n sizeClass,\n variant === \"sheet\" && SHEET_CLASSES,\n className,\n )}\n {...props}\n >\n {children}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n );\n },\n);\nDrawerContent.displayName = \"DrawerContent\";\n\n/** Props for the {@link DrawerHeader} component. */\nexport interface DrawerHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Whether to show a built-in close (X) button. @default true */\n showClose?: boolean;\n /** Accessible label for the close button. @default \"Close drawer\" */\n closeLabel?: string;\n}\n\n/**\n * A semantic header area for the drawer, typically containing a title and description.\n * Renders a built-in close button by default.\n */\nexport const DrawerHeader = React.forwardRef<HTMLDivElement, DrawerHeaderProps>(\n ({ className, showClose = true, closeLabel = \"Close drawer\", children, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex items-center gap-2 p-4\", className)} {...props}>\n <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">{children}</div>\n {showClose && (\n <DialogPrimitive.Close asChild>\n <IconButton\n icon={<CloseIcon />}\n aria-label={closeLabel}\n variant=\"secondary\"\n size=\"32\"\n className=\"shrink-0\"\n />\n </DialogPrimitive.Close>\n )}\n </div>\n ),\n);\nDrawerHeader.displayName = \"DrawerHeader\";\n\n/** Props for the {@link DrawerFooter} component. */\nexport interface DrawerFooterProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/** A semantic footer area for the drawer, typically containing action buttons. */\nexport const DrawerFooter = React.forwardRef<HTMLDivElement, DrawerFooterProps>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex flex-col gap-2 p-4\", className)} {...props} />\n ),\n);\nDrawerFooter.displayName = \"DrawerFooter\";\n\n/** Props for the {@link DrawerTitle} component. */\nexport interface DrawerTitleProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title> {}\n\n/** An accessible title for the drawer. Required for screen readers. */\nexport const DrawerTitle = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Title>,\n DrawerTitleProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\"typography-body-default-16px-semibold truncate text-content-primary\", className)}\n {...props}\n />\n));\nDrawerTitle.displayName = \"DrawerTitle\";\n\n/** Props for the {@link DrawerDescription} component. */\nexport interface DrawerDescriptionProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description> {}\n\n/** An accessible description for the drawer, providing supplementary context. */\nexport const DrawerDescription = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Description>,\n DrawerDescriptionProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"typography-body-small-14px-regular text-content-secondary\", className)}\n {...props}\n />\n));\nDrawerDescription.displayName = \"DrawerDescription\";\n"],"names":["React","jsx","DialogPrimitive","useSuppressClickAfterDrag","cn","jsxs","IconButton","CloseIcon"],"mappings":"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"}
|
|
@@ -175,6 +175,7 @@ const DropdownMenuItem = React__namespace.forwardRef(
|
|
|
175
175
|
destructive,
|
|
176
176
|
leadingIcon,
|
|
177
177
|
trailingIcon,
|
|
178
|
+
description,
|
|
178
179
|
selected,
|
|
179
180
|
className,
|
|
180
181
|
children,
|
|
@@ -182,8 +183,10 @@ const DropdownMenuItem = React__namespace.forwardRef(
|
|
|
182
183
|
...props
|
|
183
184
|
}, ref) => {
|
|
184
185
|
const normalizedSize = SIZE_NORMALIZED[size];
|
|
186
|
+
const hasDescription = description != null;
|
|
185
187
|
const itemClassName = cn.cn(
|
|
186
|
-
"flex w-full cursor-pointer
|
|
188
|
+
"flex w-full cursor-pointer gap-2 rounded-xs px-3 outline-none",
|
|
189
|
+
hasDescription ? "items-start" : "items-center",
|
|
187
190
|
ITEM_SIZE_CLASSES[normalizedSize],
|
|
188
191
|
"data-[highlighted]:bg-neutral-alphas-50",
|
|
189
192
|
"data-[disabled]:cursor-not-allowed data-[disabled]:text-content-disabled",
|
|
@@ -198,10 +201,23 @@ const DropdownMenuItem = React__namespace.forwardRef(
|
|
|
198
201
|
if (asChild) {
|
|
199
202
|
return /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuPrimitive__namespace.Item, { ref, asChild: true, className: itemClassName, ...props, children });
|
|
200
203
|
}
|
|
204
|
+
const iconAlignClassName = hasDescription ? "flex shrink-0 items-center pt-1" : null;
|
|
201
205
|
return /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuPrimitive__namespace.Item, { ref, className: itemClassName, ...props, children: [
|
|
202
|
-
leadingIcon,
|
|
203
|
-
/* @__PURE__ */ jsxRuntime.
|
|
204
|
-
|
|
206
|
+
leadingIcon != null && (hasDescription ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: iconAlignClassName, children: leadingIcon }) : leadingIcon),
|
|
207
|
+
hasDescription ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
|
|
208
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children }),
|
|
209
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
210
|
+
"span",
|
|
211
|
+
{
|
|
212
|
+
className: cn.cn(
|
|
213
|
+
"typography-body-small-14px-regular truncate",
|
|
214
|
+
selected ? "text-content-primary-inverted" : "text-content-secondary"
|
|
215
|
+
),
|
|
216
|
+
children: description
|
|
217
|
+
}
|
|
218
|
+
)
|
|
219
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children }),
|
|
220
|
+
trailingIcon != null && (hasDescription ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: iconAlignClassName, children: trailingIcon }) : trailingIcon)
|
|
205
221
|
] });
|
|
206
222
|
}
|
|
207
223
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DropdownMenu.cjs","sources":["../../../../src/components/DropdownMenu/DropdownMenu.tsx"],"sourcesContent":["import * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { useControllableState } from \"@radix-ui/react-use-controllable-state\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { FLOATING_CONTENT_COLLISION_PADDING } from \"../../utils/floatingContentCollisionPadding\";\nimport { IconButton } from \"../IconButton/IconButton\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\nimport { SearchIcon } from \"../Icons/SearchIcon\";\n\n// Movement, in CSS px, above which a touch press-and-release counts as a drag.\nconst TAP_MOVEMENT_THRESHOLD_PX = 10;\n\n// Keys that the menu must keep handling even when focus is inside a child\n// input — arrows move the highlight into the list, Tab leaves the menu, and\n// Enter / Escape close it.\nconst NAVIGATION_KEYS = new Set([\n \"ArrowDown\",\n \"ArrowUp\",\n \"ArrowLeft\",\n \"ArrowRight\",\n \"Escape\",\n \"Tab\",\n \"Enter\",\n]);\n\ntype ActiveTap = {\n pointerId: number;\n x: number;\n y: number;\n movedPastThreshold: boolean;\n};\n\n// Lets DropdownMenuTrigger toggle the menu directly so it can gate on touch\n// movement — see radix-ui/primitives#1912.\nconst ToggleOpenContext = React.createContext<\n ((updater: (prev: boolean) => boolean) => void) | null\n>(null);\n\n/** Props for the {@link DropdownMenu} root component. */\nexport interface DropdownMenuProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Root> {}\n\n/** Root component that manages open/close state for a dropdown menu. */\nexport function DropdownMenu({\n open: openProp,\n defaultOpen,\n onOpenChange,\n children,\n ...props\n}: DropdownMenuProps) {\n const [open = false, setOpen] = useControllableState({\n prop: openProp,\n defaultProp: defaultOpen ?? false,\n onChange: onOpenChange,\n });\n\n return (\n <ToggleOpenContext.Provider value={setOpen}>\n <DropdownMenuPrimitive.Root open={open} onOpenChange={setOpen} {...props}>\n {children}\n </DropdownMenuPrimitive.Root>\n </ToggleOpenContext.Provider>\n );\n}\n\n/** Props for the {@link DropdownMenuTrigger} component. */\nexport type DropdownMenuTriggerProps = React.ComponentPropsWithoutRef<\n typeof DropdownMenuPrimitive.Trigger\n>;\n\n/**\n * The element that toggles the dropdown menu when clicked.\n *\n * On touch devices, the menu only opens if the press-and-release stays within\n * a small movement threshold. A drag that incidentally ends over the trigger\n * (common when scrolling a feed on Android Chrome) is ignored. Mouse and\n * keyboard interactions are unchanged.\n */\nexport const DropdownMenuTrigger = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Trigger>,\n DropdownMenuTriggerProps\n>((props, ref) => {\n const toggleOpen = React.useContext(ToggleOpenContext);\n const tapRef = React.useRef<ActiveTap | null>(null);\n\n // Used outside our DropdownMenu wrapper — fall through to Radix defaults.\n if (toggleOpen === null) {\n return <DropdownMenuPrimitive.Trigger {...props} ref={ref} />;\n }\n\n return (\n <DropdownMenuPrimitive.Trigger\n {...props}\n ref={ref}\n onPointerDown={(event) => {\n props.onPointerDown?.(event);\n if (event.pointerType === \"mouse\" || props.disabled) return;\n // Keep pointerup / pointercancel on this element if the finger drifts off.\n // Optional because jsdom (used in tests) doesn't implement it.\n event.currentTarget.setPointerCapture?.(event.pointerId);\n tapRef.current = {\n pointerId: event.pointerId,\n x: event.clientX,\n y: event.clientY,\n movedPastThreshold: false,\n };\n // preventDefault stops Radix's pointerdown open path via composeEventHandlers.\n event.preventDefault();\n }}\n onPointerMove={(event) => {\n props.onPointerMove?.(event);\n const tap = tapRef.current;\n if (tap === null || event.pointerId !== tap.pointerId || tap.movedPastThreshold) {\n return;\n }\n const dx = event.clientX - tap.x;\n const dy = event.clientY - tap.y;\n if (Math.hypot(dx, dy) > TAP_MOVEMENT_THRESHOLD_PX) {\n tap.movedPastThreshold = true;\n }\n }}\n onPointerUp={(event) => {\n props.onPointerUp?.(event);\n const tap = tapRef.current;\n if (tap === null || event.pointerId !== tap.pointerId) return;\n const wasDrag = tap.movedPastThreshold;\n tapRef.current = null;\n if (!wasDrag && !props.disabled) {\n toggleOpen((prev) => !prev);\n }\n }}\n onPointerCancel={(event) => {\n props.onPointerCancel?.(event);\n const tap = tapRef.current;\n if (tap !== null && event.pointerId === tap.pointerId) {\n tapRef.current = null;\n }\n }}\n />\n );\n});\nDropdownMenuTrigger.displayName = \"DropdownMenuTrigger\";\n\n/** Props for the {@link DropdownMenuContent} component. */\nexport interface DropdownMenuContentProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content> {}\n\n/**\n * The positioned content panel rendered inside a portal.\n *\n * Override the portal z-index per-instance via `style={{ zIndex: 1500 }}` or\n * globally with the `--fanvue-ui-portal-z-index` CSS custom property.\n *\n * @example\n * ```tsx\n * <DropdownMenu>\n * <DropdownMenuTrigger asChild>\n * <Button>Open</Button>\n * </DropdownMenuTrigger>\n * <DropdownMenuContent>\n * <DropdownMenuItem>Option 1</DropdownMenuItem>\n * <DropdownMenuItem>Option 2</DropdownMenuItem>\n * </DropdownMenuContent>\n * </DropdownMenu>\n * ```\n */\nexport const DropdownMenuContent = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Content>,\n DropdownMenuContentProps\n>(\n (\n {\n className,\n style,\n sideOffset = 4,\n collisionPadding = FLOATING_CONTENT_COLLISION_PADDING,\n ...props\n },\n ref,\n ) => (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n collisionPadding={collisionPadding}\n className={cn(\n \"w-max min-w-(--radix-dropdown-menu-trigger-width) max-w-(--radix-dropdown-menu-content-available-width) overflow-y-auto rounded-sm border border-neutral-alphas-200 bg-surface-primary p-1 text-content-primary shadow-lg\",\n \"data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95\",\n \"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95\",\n \"data-[side=top]:slide-in-from-bottom-2 data-[side=bottom]:slide-in-from-top-2\",\n \"data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2\",\n className,\n )}\n style={{\n zIndex: \"var(--fanvue-ui-portal-z-index, 50)\",\n maxHeight: \"var(--radix-dropdown-menu-content-available-height)\",\n ...style,\n }}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n ),\n);\nDropdownMenuContent.displayName = \"DropdownMenuContent\";\n\n/** Props for the {@link DropdownMenuGroup} component. */\nexport type DropdownMenuGroupProps = React.ComponentPropsWithoutRef<\n typeof DropdownMenuPrimitive.Group\n>;\n\n/** Groups related menu items. Accepts an optional `DropdownMenuLabel`. */\nexport const DropdownMenuGroup = DropdownMenuPrimitive.Group;\nDropdownMenuGroup.displayName = \"DropdownMenuGroup\";\n\n/** Vertical placement of a {@link DropdownMenuLabel} within its group. */\nexport type DropdownMenuLabelPosition = \"default\" | \"top\";\n\n/** Props for the {@link DropdownMenuLabel} component. */\nexport interface DropdownMenuLabelProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> {\n /**\n * Vertical placement within the surrounding group. `\"top\"` is used for the\n * first label directly under a header; `\"default\"` adds extra top padding to\n * separate it from preceding items. @default \"default\"\n */\n position?: DropdownMenuLabelPosition;\n}\n\n/** A non-interactive label that groups related items within a menu. */\nexport const DropdownMenuLabel = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Label>,\n DropdownMenuLabelProps\n>(({ className, position = \"default\", ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n className={cn(\n \"typography-description-12px-regular flex items-center px-3 text-content-secondary\",\n position === \"top\" ? \"py-2\" : \"pb-2 pt-4\",\n className,\n )}\n {...props}\n />\n));\nDropdownMenuLabel.displayName = \"DropdownMenuLabel\";\n\n/**\n * Height preset for a dropdown menu item.\n *\n * `\"40\"` (default) and `\"32\"` are the v2 numeric tokens that mirror the Figma\n * design system. `\"sm\"` and `\"md\"` are deprecated aliases retained for\n * backwards compatibility — `\"sm\"` maps to `\"32\"`, `\"md\"` maps to `\"40\"`.\n */\nexport type DropdownMenuItemSize =\n | \"40\"\n | \"32\"\n /** @deprecated Use `\"32\"` instead. */\n | \"sm\"\n /** @deprecated Use `\"40\"` instead. */\n | \"md\";\n\nconst SIZE_NORMALIZED: Record<DropdownMenuItemSize, \"40\" | \"32\"> = {\n \"40\": \"40\",\n md: \"40\",\n \"32\": \"32\",\n sm: \"32\",\n};\n\nconst ITEM_SIZE_CLASSES: Record<\"40\" | \"32\", string> = {\n \"40\": \"min-h-10 py-2 typography-body-default-16px-regular\",\n \"32\": \"min-h-8 py-[7px] typography-body-small-14px-regular\",\n};\n\nconst ITEM_SELECTED_TYPOGRAPHY: Record<\"40\" | \"32\", string> = {\n \"40\": \"typography-body-default-16px-semibold\",\n \"32\": \"typography-body-small-14px-semibold\",\n};\n\nexport interface DropdownMenuItemProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> {\n /** Height of the menu item row. @default \"40\" */\n size?: DropdownMenuItemSize;\n /** Applies the destructive (error) treatment. Use for irreversible actions. @default false */\n destructive?: boolean;\n /** Icon (or other node) rendered before the label. */\n leadingIcon?: React.ReactNode;\n /** Icon (or other node) rendered after the label. */\n trailingIcon?: React.ReactNode;\n /** Marks the item as the current selection in a single-select menu. @default false */\n selected?: boolean;\n}\n\n/**\n * An individual item within a {@link DropdownMenuContent}.\n *\n * @example\n * ```tsx\n * <DropdownMenuItem>Edit profile</DropdownMenuItem>\n * <DropdownMenuItem destructive>Delete</DropdownMenuItem>\n * <DropdownMenuItem leadingIcon={<EditIcon />}>Edit</DropdownMenuItem>\n *\n * // As a link\n * <DropdownMenuItem asChild>\n * <a href=\"/settings\">Settings</a>\n * </DropdownMenuItem>\n * ```\n */\nexport const DropdownMenuItem = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Item>,\n DropdownMenuItemProps\n>(\n (\n {\n size = \"40\",\n destructive,\n leadingIcon,\n trailingIcon,\n selected,\n className,\n children,\n asChild,\n ...props\n },\n ref,\n ) => {\n const normalizedSize = SIZE_NORMALIZED[size];\n const itemClassName = cn(\n \"flex w-full cursor-pointer items-center gap-2 rounded-xs px-3 outline-none\",\n ITEM_SIZE_CLASSES[normalizedSize],\n \"data-[highlighted]:bg-neutral-alphas-50\",\n \"data-[disabled]:cursor-not-allowed data-[disabled]:text-content-disabled\",\n destructive && \"text-error-content\",\n selected && [\n \"bg-buttons-primary-default text-content-primary-inverted\",\n \"data-[highlighted]:bg-buttons-primary-default\",\n ITEM_SELECTED_TYPOGRAPHY[normalizedSize],\n ],\n className,\n );\n\n if (asChild) {\n return (\n <DropdownMenuPrimitive.Item ref={ref} asChild className={itemClassName} {...props}>\n {children}\n </DropdownMenuPrimitive.Item>\n );\n }\n\n return (\n <DropdownMenuPrimitive.Item ref={ref} className={itemClassName} {...props}>\n {leadingIcon}\n <span className=\"min-w-0 flex-1 truncate\">{children}</span>\n {trailingIcon}\n </DropdownMenuPrimitive.Item>\n );\n },\n);\nDropdownMenuItem.displayName = \"DropdownMenuItem\";\n\n/** Props for the {@link DropdownMenuSeparator} component. */\nexport interface DropdownMenuSeparatorProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator> {}\n\n/** Visual separator between groups of items. */\nexport const DropdownMenuSeparator = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Separator>,\n DropdownMenuSeparatorProps\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n className={cn(\"my-1 h-px bg-neutral-alphas-200\", className)}\n {...props}\n />\n));\nDropdownMenuSeparator.displayName = \"DropdownMenuSeparator\";\n\n/** Header type. `\"default\"` shows a title; `\"search\"` shows a search input. */\nexport type DropdownMenuHeaderType = \"default\" | \"search\";\n\n/** Header height preset. Matches the menu item sizing scale. */\nexport type DropdownMenuHeaderSize = \"40\" | \"32\";\n\n/** Search-input configuration for {@link DropdownMenuHeader} when `type=\"search\"`. */\nexport interface DropdownMenuHeaderSearchProps {\n /** Controlled value of the search input. */\n value?: string;\n /** Uncontrolled default value. */\n defaultValue?: string;\n /** Fires when the input value changes. */\n onChange?: (value: string) => void;\n /** Placeholder text shown when the input is empty. @default \"Search…\" */\n placeholder?: string;\n /** Accessible label for the search input. @default \"Search\" */\n \"aria-label\"?: string;\n}\n\nexport interface DropdownMenuHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Visual type. `\"default\"` shows a title; `\"search\"` shows a search input. @default \"default\" */\n type?: DropdownMenuHeaderType;\n /** Height preset for the header row. @default \"40\" */\n size?: DropdownMenuHeaderSize;\n /** Title text shown when `type=\"default\"`. Ignored if `children` is provided. */\n title?: string;\n /** Configuration for the embedded search input when `type=\"search\"`. */\n searchProps?: DropdownMenuHeaderSearchProps;\n /** Whether to render the close icon button on the right. @default true */\n showClose?: boolean;\n /** Fires when the close icon button is activated. */\n onClose?: () => void;\n /** Accessible label for the close button. @default \"Close menu\" */\n closeLabel?: string;\n}\n\n/**\n * Optional header rendered at the top of a {@link DropdownMenuContent}. Use\n * `type=\"default\"` to title the menu, or `type=\"search\"` to embed a search\n * input for filtering long lists.\n *\n * Renders an inset separator beneath the row so it slots cleanly above the\n * first group of items.\n *\n * @example\n * ```tsx\n * <DropdownMenuContent>\n * <DropdownMenuHeader title=\"Sort by\" onClose={() => setOpen(false)} />\n * <DropdownMenuItem>Newest</DropdownMenuItem>\n * <DropdownMenuItem>Oldest</DropdownMenuItem>\n * </DropdownMenuContent>\n * ```\n */\nexport const DropdownMenuHeader = React.forwardRef<HTMLDivElement, DropdownMenuHeaderProps>(\n (\n {\n type = \"default\",\n size = \"40\",\n title,\n searchProps,\n showClose = true,\n onClose,\n closeLabel = \"Close menu\",\n className,\n children,\n ...props\n },\n ref,\n ) => {\n const titleTypography =\n size === \"32\"\n ? \"typography-body-small-14px-semibold\"\n : \"typography-body-default-16px-semibold\";\n const toggleOpen = React.useContext(ToggleOpenContext);\n\n const handleClose = () => {\n onClose?.();\n // Also dismiss the Radix menu when used in uncontrolled mode — otherwise\n // the close button would look broken to consumers that don't wire up\n // `open` / `onOpenChange` themselves.\n toggleOpen?.(() => false);\n };\n\n return (\n <div\n ref={ref}\n className={cn(\n \"flex flex-col px-1 pt-1 mb-1\",\n // Search needs an 8px gap between the input and the divider; the\n // default (title) variant uses 4px because the title baseline sits\n // closer to the divider naturally.\n type === \"search\" ? \"gap-2\" : \"gap-1\",\n className,\n )}\n {...props}\n >\n <div className=\"flex items-center gap-4 pl-2\">\n {type === \"default\" ? (\n <div className={cn(\"min-w-0 flex-1 truncate text-content-primary\", titleTypography)}>\n {children ?? title}\n </div>\n ) : (\n <SearchInput {...searchProps} />\n )}\n {showClose && (\n <IconButton\n variant=\"tertiary\"\n size=\"32\"\n icon={<CloseIcon />}\n onClick={handleClose}\n aria-label={closeLabel}\n />\n )}\n </div>\n <DropdownMenuSeparator className=\"my-0\" />\n </div>\n );\n },\n);\nDropdownMenuHeader.displayName = \"DropdownMenuHeader\";\n\nfunction SearchInput({\n value,\n defaultValue,\n onChange,\n placeholder = \"Search\\u2026\",\n \"aria-label\": ariaLabel = \"Search\",\n}: DropdownMenuHeaderSearchProps = {}) {\n return (\n <label\n className={cn(\n \"flex min-w-0 flex-1 items-center gap-2 rounded-xs border border-border-primary\",\n \"bg-neutral-alphas-50 px-3 py-1 text-content-primary\",\n \"focus-within:shadow-focus-ring focus-within:outline-none\",\n )}\n >\n <SearchIcon className=\"size-4 shrink-0 text-content-tertiary\" aria-hidden=\"true\" />\n <input\n type=\"search\"\n className={cn(\n \"typography-body-default-16px-regular min-w-0 flex-1 bg-transparent outline-none\",\n \"placeholder:text-content-tertiary\",\n )}\n value={value}\n defaultValue={defaultValue}\n placeholder={placeholder}\n aria-label={ariaLabel}\n onChange={(event) => onChange?.(event.target.value)}\n // Radix DropdownMenu listens for keystrokes on Content for its\n // typeahead (typing letters jumps focus to a matching item). That\n // listener steals focus from the input after the first letter, so we\n // stop character keys from bubbling. Navigation keys (arrows / Tab /\n // Escape / Enter) are still allowed through so the user can leave the\n // input for the list or close the menu. Pointer events are stopped so\n // clicking back into the input doesn't fight the menu's focus\n // management either.\n onKeyDown={(event) => {\n if (!NAVIGATION_KEYS.has(event.key)) event.stopPropagation();\n }}\n onPointerDown={(event) => event.stopPropagation()}\n onMouseDown={(event) => event.stopPropagation()}\n />\n </label>\n );\n}\n\n/** Props for the {@link DropdownMenuRadioGroup} component. */\nexport interface DropdownMenuRadioGroupProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioGroup> {}\n\n/**\n * Groups {@link DropdownMenuRadioItem} children so they behave as a\n * single-select set. Controlled via `value`/`onValueChange`.\n *\n * @example\n * ```tsx\n * <DropdownMenuRadioGroup value={sort} onValueChange={setSort}>\n * <DropdownMenuRadioItem value=\"newest\">Newest first</DropdownMenuRadioItem>\n * <DropdownMenuRadioItem value=\"oldest\">Oldest first</DropdownMenuRadioItem>\n * </DropdownMenuRadioGroup>\n * ```\n */\nexport const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\n/** Height preset for a {@link DropdownMenuRadioItem}. */\nexport type DropdownMenuRadioItemSize = \"40\";\n\nexport interface DropdownMenuRadioItemProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem> {\n /** Optional secondary text shown below the title. */\n helper?: string;\n /** Height of the item row. @default \"40\" */\n size?: DropdownMenuRadioItemSize;\n}\n\n/**\n * A single radio-style choice within a {@link DropdownMenuRadioGroup}. Shows\n * a circular indicator that fills when selected, plus an optional helper line\n * underneath the title.\n */\nexport const DropdownMenuRadioItem = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.RadioItem>,\n DropdownMenuRadioItemProps\n>(({ className, children, helper, size: _size = \"40\", ...props }, ref) => {\n return (\n <DropdownMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n \"group flex w-full cursor-pointer items-start gap-3 rounded-xs px-4 py-2 outline-none\",\n \"data-[highlighted]:bg-neutral-alphas-50\",\n \"data-[disabled]:cursor-not-allowed data-[disabled]:text-content-disabled\",\n \"data-[state=checked]:bg-buttons-primary-default data-[state=checked]:text-content-primary-inverted\",\n \"data-[state=checked]:data-[highlighted]:bg-buttons-primary-default\",\n className,\n )}\n {...props}\n >\n <span\n className={cn(\n \"mt-1 flex size-4 shrink-0 items-center justify-center rounded-full border border-icons-primary\",\n \"group-data-[disabled]:border-content-disabled\",\n \"group-data-[state=checked]:border-icons-primary-inverted\",\n )}\n aria-hidden=\"true\"\n >\n <DropdownMenuPrimitive.ItemIndicator asChild>\n <span className=\"size-2 rounded-full bg-content-primary-inverted\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n <span className=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span className=\"typography-body-default-16px-semibold truncate\">{children}</span>\n {helper && (\n <span\n className={cn(\n \"typography-description-12px-regular text-content-secondary\",\n \"group-data-[state=checked]:text-content-primary-inverted\",\n \"group-data-[disabled]:text-content-disabled\",\n )}\n >\n {helper}\n </span>\n )}\n </span>\n </DropdownMenuPrimitive.RadioItem>\n );\n});\nDropdownMenuRadioItem.displayName = \"DropdownMenuRadioItem\";\n"],"names":["React","useControllableState","jsx","DropdownMenuPrimitive","FLOATING_CONTENT_COLLISION_PADDING","cn","jsxs","IconButton","CloseIcon","SearchIcon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DropdownMenu.cjs","sources":["../../../../src/components/DropdownMenu/DropdownMenu.tsx"],"sourcesContent":["import * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { useControllableState } from \"@radix-ui/react-use-controllable-state\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { FLOATING_CONTENT_COLLISION_PADDING } from \"../../utils/floatingContentCollisionPadding\";\nimport { IconButton } from \"../IconButton/IconButton\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\nimport { SearchIcon } from \"../Icons/SearchIcon\";\n\n// Movement, in CSS px, above which a touch press-and-release counts as a drag.\nconst TAP_MOVEMENT_THRESHOLD_PX = 10;\n\n// Keys that the menu must keep handling even when focus is inside a child\n// input — arrows move the highlight into the list, Tab leaves the menu, and\n// Enter / Escape close it.\nconst NAVIGATION_KEYS = new Set([\n \"ArrowDown\",\n \"ArrowUp\",\n \"ArrowLeft\",\n \"ArrowRight\",\n \"Escape\",\n \"Tab\",\n \"Enter\",\n]);\n\ntype ActiveTap = {\n pointerId: number;\n x: number;\n y: number;\n movedPastThreshold: boolean;\n};\n\n// Lets DropdownMenuTrigger toggle the menu directly so it can gate on touch\n// movement — see radix-ui/primitives#1912.\nconst ToggleOpenContext = React.createContext<\n ((updater: (prev: boolean) => boolean) => void) | null\n>(null);\n\n/** Props for the {@link DropdownMenu} root component. */\nexport interface DropdownMenuProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Root> {}\n\n/** Root component that manages open/close state for a dropdown menu. */\nexport function DropdownMenu({\n open: openProp,\n defaultOpen,\n onOpenChange,\n children,\n ...props\n}: DropdownMenuProps) {\n const [open = false, setOpen] = useControllableState({\n prop: openProp,\n defaultProp: defaultOpen ?? false,\n onChange: onOpenChange,\n });\n\n return (\n <ToggleOpenContext.Provider value={setOpen}>\n <DropdownMenuPrimitive.Root open={open} onOpenChange={setOpen} {...props}>\n {children}\n </DropdownMenuPrimitive.Root>\n </ToggleOpenContext.Provider>\n );\n}\n\n/** Props for the {@link DropdownMenuTrigger} component. */\nexport type DropdownMenuTriggerProps = React.ComponentPropsWithoutRef<\n typeof DropdownMenuPrimitive.Trigger\n>;\n\n/**\n * The element that toggles the dropdown menu when clicked.\n *\n * On touch devices, the menu only opens if the press-and-release stays within\n * a small movement threshold. A drag that incidentally ends over the trigger\n * (common when scrolling a feed on Android Chrome) is ignored. Mouse and\n * keyboard interactions are unchanged.\n */\nexport const DropdownMenuTrigger = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Trigger>,\n DropdownMenuTriggerProps\n>((props, ref) => {\n const toggleOpen = React.useContext(ToggleOpenContext);\n const tapRef = React.useRef<ActiveTap | null>(null);\n\n // Used outside our DropdownMenu wrapper — fall through to Radix defaults.\n if (toggleOpen === null) {\n return <DropdownMenuPrimitive.Trigger {...props} ref={ref} />;\n }\n\n return (\n <DropdownMenuPrimitive.Trigger\n {...props}\n ref={ref}\n onPointerDown={(event) => {\n props.onPointerDown?.(event);\n if (event.pointerType === \"mouse\" || props.disabled) return;\n // Keep pointerup / pointercancel on this element if the finger drifts off.\n // Optional because jsdom (used in tests) doesn't implement it.\n event.currentTarget.setPointerCapture?.(event.pointerId);\n tapRef.current = {\n pointerId: event.pointerId,\n x: event.clientX,\n y: event.clientY,\n movedPastThreshold: false,\n };\n // preventDefault stops Radix's pointerdown open path via composeEventHandlers.\n event.preventDefault();\n }}\n onPointerMove={(event) => {\n props.onPointerMove?.(event);\n const tap = tapRef.current;\n if (tap === null || event.pointerId !== tap.pointerId || tap.movedPastThreshold) {\n return;\n }\n const dx = event.clientX - tap.x;\n const dy = event.clientY - tap.y;\n if (Math.hypot(dx, dy) > TAP_MOVEMENT_THRESHOLD_PX) {\n tap.movedPastThreshold = true;\n }\n }}\n onPointerUp={(event) => {\n props.onPointerUp?.(event);\n const tap = tapRef.current;\n if (tap === null || event.pointerId !== tap.pointerId) return;\n const wasDrag = tap.movedPastThreshold;\n tapRef.current = null;\n if (!wasDrag && !props.disabled) {\n toggleOpen((prev) => !prev);\n }\n }}\n onPointerCancel={(event) => {\n props.onPointerCancel?.(event);\n const tap = tapRef.current;\n if (tap !== null && event.pointerId === tap.pointerId) {\n tapRef.current = null;\n }\n }}\n />\n );\n});\nDropdownMenuTrigger.displayName = \"DropdownMenuTrigger\";\n\n/** Props for the {@link DropdownMenuContent} component. */\nexport interface DropdownMenuContentProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content> {}\n\n/**\n * The positioned content panel rendered inside a portal.\n *\n * Override the portal z-index per-instance via `style={{ zIndex: 1500 }}` or\n * globally with the `--fanvue-ui-portal-z-index` CSS custom property.\n *\n * @example\n * ```tsx\n * <DropdownMenu>\n * <DropdownMenuTrigger asChild>\n * <Button>Open</Button>\n * </DropdownMenuTrigger>\n * <DropdownMenuContent>\n * <DropdownMenuItem>Option 1</DropdownMenuItem>\n * <DropdownMenuItem>Option 2</DropdownMenuItem>\n * </DropdownMenuContent>\n * </DropdownMenu>\n * ```\n */\nexport const DropdownMenuContent = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Content>,\n DropdownMenuContentProps\n>(\n (\n {\n className,\n style,\n sideOffset = 4,\n collisionPadding = FLOATING_CONTENT_COLLISION_PADDING,\n ...props\n },\n ref,\n ) => (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n collisionPadding={collisionPadding}\n className={cn(\n \"w-max min-w-(--radix-dropdown-menu-trigger-width) max-w-(--radix-dropdown-menu-content-available-width) overflow-y-auto rounded-sm border border-neutral-alphas-200 bg-surface-primary p-1 text-content-primary shadow-lg\",\n \"data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95\",\n \"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95\",\n \"data-[side=top]:slide-in-from-bottom-2 data-[side=bottom]:slide-in-from-top-2\",\n \"data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2\",\n className,\n )}\n style={{\n zIndex: \"var(--fanvue-ui-portal-z-index, 50)\",\n maxHeight: \"var(--radix-dropdown-menu-content-available-height)\",\n ...style,\n }}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n ),\n);\nDropdownMenuContent.displayName = \"DropdownMenuContent\";\n\n/** Props for the {@link DropdownMenuGroup} component. */\nexport type DropdownMenuGroupProps = React.ComponentPropsWithoutRef<\n typeof DropdownMenuPrimitive.Group\n>;\n\n/** Groups related menu items. Accepts an optional `DropdownMenuLabel`. */\nexport const DropdownMenuGroup = DropdownMenuPrimitive.Group;\nDropdownMenuGroup.displayName = \"DropdownMenuGroup\";\n\n/** Vertical placement of a {@link DropdownMenuLabel} within its group. */\nexport type DropdownMenuLabelPosition = \"default\" | \"top\";\n\n/** Props for the {@link DropdownMenuLabel} component. */\nexport interface DropdownMenuLabelProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> {\n /**\n * Vertical placement within the surrounding group. `\"top\"` is used for the\n * first label directly under a header; `\"default\"` adds extra top padding to\n * separate it from preceding items. @default \"default\"\n */\n position?: DropdownMenuLabelPosition;\n}\n\n/** A non-interactive label that groups related items within a menu. */\nexport const DropdownMenuLabel = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Label>,\n DropdownMenuLabelProps\n>(({ className, position = \"default\", ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n className={cn(\n \"typography-description-12px-regular flex items-center px-3 text-content-secondary\",\n position === \"top\" ? \"py-2\" : \"pb-2 pt-4\",\n className,\n )}\n {...props}\n />\n));\nDropdownMenuLabel.displayName = \"DropdownMenuLabel\";\n\n/**\n * Height preset for a dropdown menu item.\n *\n * `\"40\"` (default) and `\"32\"` are the v2 numeric tokens that mirror the Figma\n * design system. `\"sm\"` and `\"md\"` are deprecated aliases retained for\n * backwards compatibility — `\"sm\"` maps to `\"32\"`, `\"md\"` maps to `\"40\"`.\n */\nexport type DropdownMenuItemSize =\n | \"40\"\n | \"32\"\n /** @deprecated Use `\"32\"` instead. */\n | \"sm\"\n /** @deprecated Use `\"40\"` instead. */\n | \"md\";\n\nconst SIZE_NORMALIZED: Record<DropdownMenuItemSize, \"40\" | \"32\"> = {\n \"40\": \"40\",\n md: \"40\",\n \"32\": \"32\",\n sm: \"32\",\n};\n\nconst ITEM_SIZE_CLASSES: Record<\"40\" | \"32\", string> = {\n \"40\": \"min-h-10 py-2 typography-body-default-16px-regular\",\n \"32\": \"min-h-8 py-[7px] typography-body-small-14px-regular\",\n};\n\nconst ITEM_SELECTED_TYPOGRAPHY: Record<\"40\" | \"32\", string> = {\n \"40\": \"typography-body-default-16px-semibold\",\n \"32\": \"typography-body-small-14px-semibold\",\n};\n\nexport interface DropdownMenuItemProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> {\n /** Height of the menu item row. @default \"40\" */\n size?: DropdownMenuItemSize;\n /** Applies the destructive (error) treatment. Use for irreversible actions. @default false */\n destructive?: boolean;\n /** Icon (or other node) rendered before the label. */\n leadingIcon?: React.ReactNode;\n /** Icon (or other node) rendered after the label. */\n trailingIcon?: React.ReactNode;\n /**\n * Optional secondary text rendered on a second line below the label. When\n * provided, the row switches to a two-line layout and the leading/trailing\n * icons align to the title line (top) rather than the row's vertical centre.\n */\n description?: React.ReactNode;\n /** Marks the item as the current selection in a single-select menu. @default false */\n selected?: boolean;\n}\n\n/**\n * An individual item within a {@link DropdownMenuContent}.\n *\n * @example\n * ```tsx\n * <DropdownMenuItem>Edit profile</DropdownMenuItem>\n * <DropdownMenuItem destructive>Delete</DropdownMenuItem>\n * <DropdownMenuItem leadingIcon={<EditIcon />}>Edit</DropdownMenuItem>\n *\n * // As a link\n * <DropdownMenuItem asChild>\n * <a href=\"/settings\">Settings</a>\n * </DropdownMenuItem>\n * ```\n */\nexport const DropdownMenuItem = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Item>,\n DropdownMenuItemProps\n>(\n (\n {\n size = \"40\",\n destructive,\n leadingIcon,\n trailingIcon,\n description,\n selected,\n className,\n children,\n asChild,\n ...props\n },\n ref,\n ) => {\n const normalizedSize = SIZE_NORMALIZED[size];\n const hasDescription = description != null;\n const itemClassName = cn(\n \"flex w-full cursor-pointer gap-2 rounded-xs px-3 outline-none\",\n hasDescription ? \"items-start\" : \"items-center\",\n ITEM_SIZE_CLASSES[normalizedSize],\n \"data-[highlighted]:bg-neutral-alphas-50\",\n \"data-[disabled]:cursor-not-allowed data-[disabled]:text-content-disabled\",\n destructive && \"text-error-content\",\n selected && [\n \"bg-buttons-primary-default text-content-primary-inverted\",\n \"data-[highlighted]:bg-buttons-primary-default\",\n ITEM_SELECTED_TYPOGRAPHY[normalizedSize],\n ],\n className,\n );\n\n if (asChild) {\n return (\n <DropdownMenuPrimitive.Item ref={ref} asChild className={itemClassName} {...props}>\n {children}\n </DropdownMenuPrimitive.Item>\n );\n }\n\n // In the two-line (description) layout, icons sit on the title's line.\n // 24px title line-height vs 16px icon → 4px (pt-1) centres the icon on it.\n const iconAlignClassName = hasDescription ? \"flex shrink-0 items-center pt-1\" : null;\n\n return (\n <DropdownMenuPrimitive.Item ref={ref} className={itemClassName} {...props}>\n {leadingIcon != null &&\n (hasDescription ? (\n <span className={iconAlignClassName!}>{leadingIcon}</span>\n ) : (\n leadingIcon\n ))}\n {hasDescription ? (\n <span className=\"flex min-w-0 flex-1 flex-col gap-0.5\">\n <span className=\"truncate\">{children}</span>\n <span\n className={cn(\n \"typography-body-small-14px-regular truncate\",\n selected ? \"text-content-primary-inverted\" : \"text-content-secondary\",\n )}\n >\n {description}\n </span>\n </span>\n ) : (\n <span className=\"min-w-0 flex-1 truncate\">{children}</span>\n )}\n {trailingIcon != null &&\n (hasDescription ? (\n <span className={iconAlignClassName!}>{trailingIcon}</span>\n ) : (\n trailingIcon\n ))}\n </DropdownMenuPrimitive.Item>\n );\n },\n);\nDropdownMenuItem.displayName = \"DropdownMenuItem\";\n\n/** Props for the {@link DropdownMenuSeparator} component. */\nexport interface DropdownMenuSeparatorProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator> {}\n\n/** Visual separator between groups of items. */\nexport const DropdownMenuSeparator = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Separator>,\n DropdownMenuSeparatorProps\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n className={cn(\"my-1 h-px bg-neutral-alphas-200\", className)}\n {...props}\n />\n));\nDropdownMenuSeparator.displayName = \"DropdownMenuSeparator\";\n\n/** Header type. `\"default\"` shows a title; `\"search\"` shows a search input. */\nexport type DropdownMenuHeaderType = \"default\" | \"search\";\n\n/** Header height preset. Matches the menu item sizing scale. */\nexport type DropdownMenuHeaderSize = \"40\" | \"32\";\n\n/** Search-input configuration for {@link DropdownMenuHeader} when `type=\"search\"`. */\nexport interface DropdownMenuHeaderSearchProps {\n /** Controlled value of the search input. */\n value?: string;\n /** Uncontrolled default value. */\n defaultValue?: string;\n /** Fires when the input value changes. */\n onChange?: (value: string) => void;\n /** Placeholder text shown when the input is empty. @default \"Search…\" */\n placeholder?: string;\n /** Accessible label for the search input. @default \"Search\" */\n \"aria-label\"?: string;\n}\n\nexport interface DropdownMenuHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Visual type. `\"default\"` shows a title; `\"search\"` shows a search input. @default \"default\" */\n type?: DropdownMenuHeaderType;\n /** Height preset for the header row. @default \"40\" */\n size?: DropdownMenuHeaderSize;\n /** Title text shown when `type=\"default\"`. Ignored if `children` is provided. */\n title?: string;\n /** Configuration for the embedded search input when `type=\"search\"`. */\n searchProps?: DropdownMenuHeaderSearchProps;\n /** Whether to render the close icon button on the right. @default true */\n showClose?: boolean;\n /** Fires when the close icon button is activated. */\n onClose?: () => void;\n /** Accessible label for the close button. @default \"Close menu\" */\n closeLabel?: string;\n}\n\n/**\n * Optional header rendered at the top of a {@link DropdownMenuContent}. Use\n * `type=\"default\"` to title the menu, or `type=\"search\"` to embed a search\n * input for filtering long lists.\n *\n * Renders an inset separator beneath the row so it slots cleanly above the\n * first group of items.\n *\n * @example\n * ```tsx\n * <DropdownMenuContent>\n * <DropdownMenuHeader title=\"Sort by\" onClose={() => setOpen(false)} />\n * <DropdownMenuItem>Newest</DropdownMenuItem>\n * <DropdownMenuItem>Oldest</DropdownMenuItem>\n * </DropdownMenuContent>\n * ```\n */\nexport const DropdownMenuHeader = React.forwardRef<HTMLDivElement, DropdownMenuHeaderProps>(\n (\n {\n type = \"default\",\n size = \"40\",\n title,\n searchProps,\n showClose = true,\n onClose,\n closeLabel = \"Close menu\",\n className,\n children,\n ...props\n },\n ref,\n ) => {\n const titleTypography =\n size === \"32\"\n ? \"typography-body-small-14px-semibold\"\n : \"typography-body-default-16px-semibold\";\n const toggleOpen = React.useContext(ToggleOpenContext);\n\n const handleClose = () => {\n onClose?.();\n // Also dismiss the Radix menu when used in uncontrolled mode — otherwise\n // the close button would look broken to consumers that don't wire up\n // `open` / `onOpenChange` themselves.\n toggleOpen?.(() => false);\n };\n\n return (\n <div\n ref={ref}\n className={cn(\n \"flex flex-col px-1 pt-1 mb-1\",\n // Search needs an 8px gap between the input and the divider; the\n // default (title) variant uses 4px because the title baseline sits\n // closer to the divider naturally.\n type === \"search\" ? \"gap-2\" : \"gap-1\",\n className,\n )}\n {...props}\n >\n <div className=\"flex items-center gap-4 pl-2\">\n {type === \"default\" ? (\n <div className={cn(\"min-w-0 flex-1 truncate text-content-primary\", titleTypography)}>\n {children ?? title}\n </div>\n ) : (\n <SearchInput {...searchProps} />\n )}\n {showClose && (\n <IconButton\n variant=\"tertiary\"\n size=\"32\"\n icon={<CloseIcon />}\n onClick={handleClose}\n aria-label={closeLabel}\n />\n )}\n </div>\n <DropdownMenuSeparator className=\"my-0\" />\n </div>\n );\n },\n);\nDropdownMenuHeader.displayName = \"DropdownMenuHeader\";\n\nfunction SearchInput({\n value,\n defaultValue,\n onChange,\n placeholder = \"Search\\u2026\",\n \"aria-label\": ariaLabel = \"Search\",\n}: DropdownMenuHeaderSearchProps = {}) {\n return (\n <label\n className={cn(\n \"flex min-w-0 flex-1 items-center gap-2 rounded-xs border border-border-primary\",\n \"bg-neutral-alphas-50 px-3 py-1 text-content-primary\",\n \"focus-within:shadow-focus-ring focus-within:outline-none\",\n )}\n >\n <SearchIcon className=\"size-4 shrink-0 text-content-tertiary\" aria-hidden=\"true\" />\n <input\n type=\"search\"\n className={cn(\n \"typography-body-default-16px-regular min-w-0 flex-1 bg-transparent outline-none\",\n \"placeholder:text-content-tertiary\",\n )}\n value={value}\n defaultValue={defaultValue}\n placeholder={placeholder}\n aria-label={ariaLabel}\n onChange={(event) => onChange?.(event.target.value)}\n // Radix DropdownMenu listens for keystrokes on Content for its\n // typeahead (typing letters jumps focus to a matching item). That\n // listener steals focus from the input after the first letter, so we\n // stop character keys from bubbling. Navigation keys (arrows / Tab /\n // Escape / Enter) are still allowed through so the user can leave the\n // input for the list or close the menu. Pointer events are stopped so\n // clicking back into the input doesn't fight the menu's focus\n // management either.\n onKeyDown={(event) => {\n if (!NAVIGATION_KEYS.has(event.key)) event.stopPropagation();\n }}\n onPointerDown={(event) => event.stopPropagation()}\n onMouseDown={(event) => event.stopPropagation()}\n />\n </label>\n );\n}\n\n/** Props for the {@link DropdownMenuRadioGroup} component. */\nexport interface DropdownMenuRadioGroupProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioGroup> {}\n\n/**\n * Groups {@link DropdownMenuRadioItem} children so they behave as a\n * single-select set. Controlled via `value`/`onValueChange`.\n *\n * @example\n * ```tsx\n * <DropdownMenuRadioGroup value={sort} onValueChange={setSort}>\n * <DropdownMenuRadioItem value=\"newest\">Newest first</DropdownMenuRadioItem>\n * <DropdownMenuRadioItem value=\"oldest\">Oldest first</DropdownMenuRadioItem>\n * </DropdownMenuRadioGroup>\n * ```\n */\nexport const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\n/** Height preset for a {@link DropdownMenuRadioItem}. */\nexport type DropdownMenuRadioItemSize = \"40\";\n\nexport interface DropdownMenuRadioItemProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem> {\n /** Optional secondary text shown below the title. */\n helper?: string;\n /** Height of the item row. @default \"40\" */\n size?: DropdownMenuRadioItemSize;\n}\n\n/**\n * A single radio-style choice within a {@link DropdownMenuRadioGroup}. Shows\n * a circular indicator that fills when selected, plus an optional helper line\n * underneath the title.\n */\nexport const DropdownMenuRadioItem = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.RadioItem>,\n DropdownMenuRadioItemProps\n>(({ className, children, helper, size: _size = \"40\", ...props }, ref) => {\n return (\n <DropdownMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n \"group flex w-full cursor-pointer items-start gap-3 rounded-xs px-4 py-2 outline-none\",\n \"data-[highlighted]:bg-neutral-alphas-50\",\n \"data-[disabled]:cursor-not-allowed data-[disabled]:text-content-disabled\",\n \"data-[state=checked]:bg-buttons-primary-default data-[state=checked]:text-content-primary-inverted\",\n \"data-[state=checked]:data-[highlighted]:bg-buttons-primary-default\",\n className,\n )}\n {...props}\n >\n <span\n className={cn(\n \"mt-1 flex size-4 shrink-0 items-center justify-center rounded-full border border-icons-primary\",\n \"group-data-[disabled]:border-content-disabled\",\n \"group-data-[state=checked]:border-icons-primary-inverted\",\n )}\n aria-hidden=\"true\"\n >\n <DropdownMenuPrimitive.ItemIndicator asChild>\n <span className=\"size-2 rounded-full bg-content-primary-inverted\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n <span className=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span className=\"typography-body-default-16px-semibold truncate\">{children}</span>\n {helper && (\n <span\n className={cn(\n \"typography-description-12px-regular text-content-secondary\",\n \"group-data-[state=checked]:text-content-primary-inverted\",\n \"group-data-[disabled]:text-content-disabled\",\n )}\n >\n {helper}\n </span>\n )}\n </span>\n </DropdownMenuPrimitive.RadioItem>\n );\n});\nDropdownMenuRadioItem.displayName = \"DropdownMenuRadioItem\";\n"],"names":["React","useControllableState","jsx","DropdownMenuPrimitive","FLOATING_CONTENT_COLLISION_PADDING","cn","jsxs","IconButton","CloseIcon","SearchIcon"],"mappings":"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"}
|
|
@@ -23,7 +23,9 @@ function _interopNamespaceDefault(e) {
|
|
|
23
23
|
const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
|
|
24
24
|
const VARIANTS = {
|
|
25
25
|
16: {
|
|
26
|
-
|
|
26
|
+
// `sw` must be set so BaseIcon strokes the checkmark; without it the path
|
|
27
|
+
// is filled into a solid wedge instead of a tick.
|
|
28
|
+
outlined: [{ d: "m3.333 8 3.334 3.333L13 5", sw: 1.333 }]
|
|
27
29
|
},
|
|
28
30
|
24: {
|
|
29
31
|
outlined: [{ d: "m5 12 5 5 9.5-9.5", sw: 1.5 }]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TickIcon.cjs","sources":["../../../../src/components/Icons/TickIcon.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { BaseIcon } from \"./BaseIcon\";\nimport type { BaseIconProps, IconVariants } from \"./types\";\n\nconst VARIANTS: IconVariants = {\n 16: {\n outlined: [{ d: \"m3.333 8 3.334 3.333L13 5\" }],\n },\n 24: {\n outlined: [{ d: \"m5 12 5 5 9.5-9.5\", sw: 1.5 }],\n },\n 32: {\n outlined: [{ d: \"m6.667 16 6.666 6.667L26 10\", sw: 2 }],\n },\n};\n\n/** Props for {@link TickIcon}. See {@link BaseIconProps} for the shared shape. */\nexport type TickIconProps = BaseIconProps;\n\n/**\n * Tick icon. Renders at sizes 16, 24, or 32 px.\n *\n * @example\n * ```tsx\n * <TickIcon size={24} />\n * ```\n */\nexport const TickIcon = React.forwardRef<SVGSVGElement, TickIconProps>((props, ref) => (\n <BaseIcon ref={ref} variants={VARIANTS} {...props} />\n));\n\nTickIcon.displayName = \"TickIcon\";\n"],"names":["React","jsx","BaseIcon"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAIA,MAAM,WAAyB;AAAA,EAC7B,IAAI;AAAA,
|
|
1
|
+
{"version":3,"file":"TickIcon.cjs","sources":["../../../../src/components/Icons/TickIcon.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { BaseIcon } from \"./BaseIcon\";\nimport type { BaseIconProps, IconVariants } from \"./types\";\n\nconst VARIANTS: IconVariants = {\n 16: {\n // `sw` must be set so BaseIcon strokes the checkmark; without it the path\n // is filled into a solid wedge instead of a tick.\n outlined: [{ d: \"m3.333 8 3.334 3.333L13 5\", sw: 1.333 }],\n },\n 24: {\n outlined: [{ d: \"m5 12 5 5 9.5-9.5\", sw: 1.5 }],\n },\n 32: {\n outlined: [{ d: \"m6.667 16 6.666 6.667L26 10\", sw: 2 }],\n },\n};\n\n/** Props for {@link TickIcon}. See {@link BaseIconProps} for the shared shape. */\nexport type TickIconProps = BaseIconProps;\n\n/**\n * Tick icon. Renders at sizes 16, 24, or 32 px.\n *\n * @example\n * ```tsx\n * <TickIcon size={24} />\n * ```\n */\nexport const TickIcon = React.forwardRef<SVGSVGElement, TickIconProps>((props, ref) => (\n <BaseIcon ref={ref} variants={VARIANTS} {...props} />\n));\n\nTickIcon.displayName = \"TickIcon\";\n"],"names":["React","jsx","BaseIcon"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAIA,MAAM,WAAyB;AAAA,EAC7B,IAAI;AAAA;AAAA;AAAA,IAGF,UAAU,CAAC,EAAE,GAAG,6BAA6B,IAAI,OAAO;AAAA,EAAA;AAAA,EAE1D,IAAI;AAAA,IACF,UAAU,CAAC,EAAE,GAAG,qBAAqB,IAAI,KAAK;AAAA,EAAA;AAAA,EAEhD,IAAI;AAAA,IACF,UAAU,CAAC,EAAE,GAAG,+BAA+B,IAAI,GAAG;AAAA,EAAA;AAE1D;AAaO,MAAM,WAAWA,iBAAM,WAAyC,CAAC,OAAO,QAC7EC,2BAAAA,IAACC,SAAAA,UAAA,EAAS,KAAU,UAAU,UAAW,GAAG,OAAO,CACpD;AAED,SAAS,cAAc;;"}
|
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
4
4
|
const jsxRuntime = require("react/jsx-runtime");
|
|
5
5
|
const React = require("react");
|
|
6
6
|
const cn = require("../../utils/cn.cjs");
|
|
7
|
+
const agenciesIcon = require("./agenciesIcon.cjs");
|
|
7
8
|
function _interopNamespaceDefault(e) {
|
|
8
9
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
9
10
|
if (e) {
|
|
@@ -27,7 +28,6 @@ const getLogoColors = (color, variant) => {
|
|
|
27
28
|
icon: "var(--color-brand-primary-default)",
|
|
28
29
|
iconInner: "var(--primitives-color-gray-black)",
|
|
29
30
|
textClass: ""
|
|
30
|
-
// Uses parent's text-content-primary
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
if (color === "decolour") {
|
|
@@ -35,7 +35,6 @@ const getLogoColors = (color, variant) => {
|
|
|
35
35
|
iconClass: "fill-[#151515] dark:fill-[#ffffff]",
|
|
36
36
|
iconInnerClass: "fill-[#ffffff] dark:fill-[#151515]",
|
|
37
37
|
textClass: ""
|
|
38
|
-
// Uses parent's text-content-primary
|
|
39
38
|
};
|
|
40
39
|
}
|
|
41
40
|
if (color === "whiteAlways") {
|
|
@@ -56,7 +55,6 @@ const getLogoColors = (color, variant) => {
|
|
|
56
55
|
icon: "var(--color-brand-primary-default)",
|
|
57
56
|
iconInner: "var(--primitives-color-gray-black)",
|
|
58
57
|
textClass: ""
|
|
59
|
-
// Default to adaptive color
|
|
60
58
|
};
|
|
61
59
|
};
|
|
62
60
|
const sizeClasses = {
|
|
@@ -68,6 +66,60 @@ const sizeClasses = {
|
|
|
68
66
|
"48": "h-12",
|
|
69
67
|
"64": "h-16"
|
|
70
68
|
};
|
|
69
|
+
const ICON_BG_PATH = "M0 11.2339C0 5.02957 5.02957 0 11.2339 0H27.7661C33.9704 0 39 5.02957 39 11.2339V27.7661C39 33.9704 33.9704 39 27.7661 39H11.2339C5.02957 39 0 33.9704 0 27.7661V11.2339Z";
|
|
70
|
+
const ICON_F_PATH = "M12.277 30.5825C11.4418 30.5825 11.0355 29.8659 11.2059 29.1153C11.4275 28.0916 12.5838 25.0548 11.7145 23.6899C10.4361 21.6938 7.25562 21.9838 6.5397 20.9602C6.02371 20.2089 6.48355 19.478 7.19738 19.0493C8.79967 18.0257 11.902 18.3157 14.9191 16.3025C16.5895 15.2106 18.1237 12.9927 18.993 11.662C20.2203 9.78527 20.7487 9.39287 23.3226 9.39287H32.3376C33.7574 9.39287 34.202 11.8036 31.8852 12.0686C31.2886 12.1368 29.6977 12.3757 27.4306 12.6487C25.2658 12.9216 20.4589 13.5728 22.351 16.6608C23.7658 18.2816 26.7488 18.0769 27.4306 19.0493C27.9238 19.7225 27.4875 20.4384 26.9505 20.7824C25.3311 21.8061 21.8737 21.6938 18.8566 23.6899C16.8111 25.0548 15.1478 28.0916 14.4659 29.1153C13.9716 29.8659 13.1293 30.5825 12.294 30.5825H12.277Z";
|
|
71
|
+
const FlatIconSVG = ({
|
|
72
|
+
className,
|
|
73
|
+
color,
|
|
74
|
+
variant
|
|
75
|
+
}) => {
|
|
76
|
+
const colors = getLogoColors(color, variant);
|
|
77
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
78
|
+
"svg",
|
|
79
|
+
{
|
|
80
|
+
viewBox: "0 0 39 39",
|
|
81
|
+
fill: "none",
|
|
82
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
83
|
+
className,
|
|
84
|
+
"aria-hidden": "true",
|
|
85
|
+
"data-testid": "logo-icon",
|
|
86
|
+
children: [
|
|
87
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
88
|
+
"path",
|
|
89
|
+
{
|
|
90
|
+
d: ICON_BG_PATH,
|
|
91
|
+
...color === "decolour" ? { className: colors.iconClass } : { fill: colors.icon }
|
|
92
|
+
}
|
|
93
|
+
),
|
|
94
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
95
|
+
"path",
|
|
96
|
+
{
|
|
97
|
+
fillRule: "evenodd",
|
|
98
|
+
clipRule: "evenodd",
|
|
99
|
+
d: ICON_F_PATH,
|
|
100
|
+
...color === "decolour" ? { className: colors.iconInnerClass } : { fill: colors.iconInner }
|
|
101
|
+
}
|
|
102
|
+
)
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
};
|
|
107
|
+
const AgenciesIconSVG = ({ className }) => {
|
|
108
|
+
const ns = React__namespace.useId().replace(/:/g, "");
|
|
109
|
+
const html = React__namespace.useMemo(
|
|
110
|
+
() => agenciesIcon.AGENCIES_ICON_SVG.replace(/id="([a-z]+)"/g, `id="$1${ns}"`).replace(/url\(#([a-z]+)\)/g, `url(#$1${ns})`).replace(/href="#([a-z]+)"/g, `href="#$1${ns}"`),
|
|
111
|
+
[ns]
|
|
112
|
+
);
|
|
113
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
114
|
+
"span",
|
|
115
|
+
{
|
|
116
|
+
className: cn.cn("inline-block aspect-square isolate", className),
|
|
117
|
+
"aria-hidden": "true",
|
|
118
|
+
"data-testid": "logo-icon",
|
|
119
|
+
dangerouslySetInnerHTML: { __html: html }
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
};
|
|
71
123
|
const WordmarkSVG = ({ className }) => {
|
|
72
124
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
73
125
|
"svg",
|
|
@@ -88,20 +140,55 @@ const WordmarkSVG = ({ className }) => {
|
|
|
88
140
|
}
|
|
89
141
|
);
|
|
90
142
|
};
|
|
143
|
+
const AgenciesWordmark = ({
|
|
144
|
+
size,
|
|
145
|
+
color,
|
|
146
|
+
textClass,
|
|
147
|
+
padTop
|
|
148
|
+
}) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
149
|
+
"div",
|
|
150
|
+
{
|
|
151
|
+
className: cn.cn("inline-flex flex-col items-end", padTop && "pt-[0.125em]"),
|
|
152
|
+
style: { fontSize: `${size}px` },
|
|
153
|
+
children: [
|
|
154
|
+
/* @__PURE__ */ jsxRuntime.jsx(WordmarkSVG, { className: cn.cn("h-[0.75em] w-auto", textClass) }),
|
|
155
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
156
|
+
"span",
|
|
157
|
+
{
|
|
158
|
+
className: "font-bold uppercase leading-none",
|
|
159
|
+
style: {
|
|
160
|
+
color: color === "decolour" ? "currentColor" : "var(--primitives-color-purple-300)",
|
|
161
|
+
fontSize: "0.25em",
|
|
162
|
+
letterSpacing: "0.05em",
|
|
163
|
+
marginTop: "0.06em"
|
|
164
|
+
},
|
|
165
|
+
children: "AGENCIES"
|
|
166
|
+
}
|
|
167
|
+
)
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
);
|
|
91
171
|
const Logo = React__namespace.forwardRef(
|
|
92
|
-
({ className, variant = "full", color = "fullColour", size, ...props }, ref) => {
|
|
172
|
+
({ className, variant = "full", color = "fullColour", version = "default", size, ...props }, ref) => {
|
|
93
173
|
const colors = getLogoColors(color, variant);
|
|
174
|
+
const isAgencies = version === "agencies";
|
|
175
|
+
const isAgenciesFull = isAgencies && variant === "full";
|
|
94
176
|
const showIcon = variant === "full" || variant === "icon" || variant === "portrait";
|
|
95
177
|
const showWordmark = variant === "full" || variant === "wordmark" || variant === "portrait";
|
|
96
|
-
const
|
|
178
|
+
const resolvedSize = size ?? (variant === "icon" ? "40" : "32");
|
|
179
|
+
const sizeClass = sizeClasses[resolvedSize];
|
|
97
180
|
const ariaProps = props["aria-label"] ? { role: "img" } : {};
|
|
181
|
+
const useGlossyIcon = isAgencies && color !== "decolour";
|
|
98
182
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
99
183
|
"div",
|
|
100
184
|
{
|
|
101
185
|
ref,
|
|
102
186
|
"data-testid": "logo",
|
|
103
187
|
className: cn.cn(
|
|
104
|
-
"inline-flex
|
|
188
|
+
"inline-flex text-content-primary",
|
|
189
|
+
// Agencies full lockup aligns the icon and wordmark by their centres while the
|
|
190
|
+
// AGENCIES label hangs below; every other case centres the row.
|
|
191
|
+
isAgenciesFull ? "items-start" : "items-center",
|
|
105
192
|
variant === "portrait" ? "flex-col gap-2" : "flex-row",
|
|
106
193
|
variant === "full" && "gap-2",
|
|
107
194
|
className
|
|
@@ -109,36 +196,23 @@ const Logo = React__namespace.forwardRef(
|
|
|
109
196
|
...ariaProps,
|
|
110
197
|
...props,
|
|
111
198
|
children: [
|
|
112
|
-
showIcon && /* @__PURE__ */ jsxRuntime.
|
|
113
|
-
|
|
199
|
+
showIcon && (useGlossyIcon ? /* @__PURE__ */ jsxRuntime.jsx(AgenciesIconSVG, { className: cn.cn("w-auto shrink-0", sizeClass) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
200
|
+
FlatIconSVG,
|
|
114
201
|
{
|
|
115
|
-
viewBox: "0 0 39 39",
|
|
116
|
-
fill: "none",
|
|
117
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
118
202
|
className: cn.cn("w-auto shrink-0", sizeClass),
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
"path",
|
|
131
|
-
{
|
|
132
|
-
fillRule: "evenodd",
|
|
133
|
-
clipRule: "evenodd",
|
|
134
|
-
d: "M12.277 30.5825C11.4418 30.5825 11.0355 29.8659 11.2059 29.1153C11.4275 28.0916 12.5838 25.0548 11.7145 23.6899C10.4361 21.6938 7.25562 21.9838 6.5397 20.9602C6.02371 20.2089 6.48355 19.478 7.19738 19.0493C8.79967 18.0257 11.902 18.3157 14.9191 16.3025C16.5895 15.2106 18.1237 12.9927 18.993 11.662C20.2203 9.78527 20.7487 9.39287 23.3226 9.39287H32.3376C33.7574 9.39287 34.202 11.8036 31.8852 12.0686C31.2886 12.1368 29.6977 12.3757 27.4306 12.6487C25.2658 12.9216 20.4589 13.5728 22.351 16.6608C23.7658 18.2816 26.7488 18.0769 27.4306 19.0493C27.9238 19.7225 27.4875 20.4384 26.9505 20.7824C25.3311 21.8061 21.8737 21.6938 18.8566 23.6899C16.8111 25.0548 15.1478 28.0916 14.4659 29.1153C13.9716 29.8659 13.1293 30.5825 12.294 30.5825H12.277Z",
|
|
135
|
-
...color === "decolour" ? { className: colors.iconInnerClass } : { fill: colors.iconInner }
|
|
136
|
-
}
|
|
137
|
-
)
|
|
138
|
-
]
|
|
203
|
+
color,
|
|
204
|
+
variant
|
|
205
|
+
}
|
|
206
|
+
)),
|
|
207
|
+
showWordmark && (isAgencies ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
208
|
+
AgenciesWordmark,
|
|
209
|
+
{
|
|
210
|
+
size: resolvedSize,
|
|
211
|
+
color,
|
|
212
|
+
textClass: colors.textClass,
|
|
213
|
+
padTop: isAgenciesFull
|
|
139
214
|
}
|
|
140
|
-
),
|
|
141
|
-
showWordmark && /* @__PURE__ */ jsxRuntime.jsx(WordmarkSVG, { className: cn.cn("w-auto", sizeClass, colors.textClass) })
|
|
215
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(WordmarkSVG, { className: cn.cn("w-auto", sizeClass, colors.textClass) }))
|
|
142
216
|
]
|
|
143
217
|
}
|
|
144
218
|
);
|