@brycks/core-front 0.3.3 → 0.3.4
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/components/feedback/Alert/Alert.cjs +1 -1
- package/dist/components/feedback/Alert/Alert.cjs.map +1 -1
- package/dist/components/feedback/Alert/Alert.js +52 -177
- package/dist/components/feedback/Alert/Alert.js.map +1 -1
- package/dist/components/form/Checkbox/Checkbox.cjs +1 -1
- package/dist/components/form/Checkbox/Checkbox.js +12 -12
- package/dist/components/form/Input/Input.cjs +1 -1
- package/dist/components/form/Input/Input.js +13 -13
- package/dist/components/form/Slider/Slider.cjs +1 -1
- package/dist/components/form/Slider/Slider.js +1 -1
- package/dist/components/form/Switch/Switch.cjs +1 -1
- package/dist/components/form/Switch/Switch.cjs.map +1 -1
- package/dist/components/form/Switch/Switch.js +70 -105
- package/dist/components/form/Switch/Switch.js.map +1 -1
- package/dist/components/layout/Card/Card.cjs +1 -1
- package/dist/components/layout/Card/Card.cjs.map +1 -1
- package/dist/components/layout/Card/Card.js +59 -121
- package/dist/components/layout/Card/Card.js.map +1 -1
- package/dist/components/navigation/Dropdown/Dropdown.cjs +1 -6
- package/dist/components/navigation/Dropdown/Dropdown.cjs.map +1 -1
- package/dist/components/navigation/Dropdown/Dropdown.js +118 -183
- package/dist/components/navigation/Dropdown/Dropdown.js.map +1 -1
- package/dist/components/navigation/Menu/Menu.cjs +1 -1
- package/dist/components/navigation/Menu/Menu.js +5 -5
- package/dist/components/navigation/Tabs/Tabs.cjs +1 -6
- package/dist/components/navigation/Tabs/Tabs.cjs.map +1 -1
- package/dist/components/navigation/Tabs/Tabs.js +92 -162
- package/dist/components/navigation/Tabs/Tabs.js.map +1 -1
- package/dist/components/primitives/Button/Button.cjs +1 -1
- package/dist/components/primitives/Button/Button.cjs.map +1 -1
- package/dist/components/primitives/Button/Button.js +72 -96
- package/dist/components/primitives/Button/Button.js.map +1 -1
- package/dist/components/primitives/Button/Button.styles.cjs +1 -1
- package/dist/components/primitives/Button/Button.styles.cjs.map +1 -1
- package/dist/components/primitives/Button/Button.styles.js +8 -317
- package/dist/components/primitives/Button/Button.styles.js.map +1 -1
- package/dist/components/utility/Badge/Badge.cjs +1 -1
- package/dist/components/utility/Badge/Badge.cjs.map +1 -1
- package/dist/components/utility/Badge/Badge.js +23 -80
- package/dist/components/utility/Badge/Badge.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
2
|
-
@keyframes brycks-dropdown-in {
|
|
3
|
-
from { opacity: 0; transform: translateY(-4px); }
|
|
4
|
-
to { opacity: 1; transform: translateY(0); }
|
|
5
|
-
}
|
|
6
|
-
`}),a.jsx("div",{ref:k,role:"menu",style:J,onKeyDown:A,tabIndex:-1,children:C})]}),document.body)]})})});K.displayName="Dropdown";const M=r.forwardRef(function({disabled:t=!1,icon:c,shortcut:l,destructive:d=!1,className:i,style:m,children:D,onClick:h,...S},C){const{close:E}=V(),j=n=>{t||(h?.(n),E())},z={display:"flex",alignItems:"center",gap:f.componentGap.lg,padding:`${f.componentPaddingY.md}px ${f.componentPaddingX.sm}px`,fontSize:$.fontSizes.base,color:t?"var(--brycks-foreground-disabled)":d?"var(--brycks-error-default)":"var(--brycks-foreground-default)",backgroundColor:"transparent",borderRadius:"var(--brycks-radius-md)",cursor:t?"not-allowed":"pointer",transition:`background-color ${v.durations.fast}ms ${v.easings.easeOut}`,outline:"none",...m},R={width:f.iconSizes.sm,height:f.iconSizes.sm,color:t?"var(--brycks-foreground-disabled)":d?"var(--brycks-error-default)":"var(--brycks-foreground-muted)",flexShrink:0},I={marginLeft:"auto",fontSize:$.fontSizes.sm,color:"var(--brycks-foreground-muted)",fontFamily:"var(--brycks-font-mono)"};return a.jsxs("div",{ref:C,role:"menuitem","aria-disabled":t,tabIndex:t?-1:0,className:x.cx("brycks-dropdown-item",t&&"brycks-dropdown-item--disabled",i),style:z,onClick:j,onMouseEnter:n=>{t||(n.currentTarget.style.backgroundColor="var(--brycks-background-muted)")},onMouseLeave:n=>{n.currentTarget.style.backgroundColor="transparent"},onFocus:n=>{n.currentTarget.style.backgroundColor="var(--brycks-background-muted)"},onBlur:n=>{n.currentTarget.style.backgroundColor="transparent"},...S,children:[c&&a.jsx("span",{style:R,children:c}),a.jsx("span",{style:{flex:1},children:D}),l&&a.jsx("span",{style:I,children:l})]})});M.displayName="DropdownItem";const F=r.forwardRef(function({className:t,style:c,...l},d){const i={height:1,backgroundColor:"var(--brycks-border-muted)",margin:`${N.spacing[1]}px 0`,...c};return a.jsx("div",{ref:d,role:"separator",className:x.cx("brycks-dropdown-divider",t),style:i,...l})});F.displayName="DropdownDivider";const B=r.forwardRef(function({className:t,style:c,children:l,...d},i){const m={padding:`${f.componentPaddingY.md}px ${f.componentPaddingX.sm}px ${N.spacing[1]}px ${f.componentPaddingX.sm}px`,fontSize:$.fontSizes.xs,fontWeight:600,color:"var(--brycks-foreground-muted)",textTransform:"uppercase",letterSpacing:"0.05em",...c};return a.jsx("div",{ref:i,className:x.cx("brycks-dropdown-label",t),style:m,...d,children:l})});B.displayName="DropdownLabel";exports.Dropdown=K;exports.DropdownDivider=F;exports.DropdownItem=M;exports.DropdownLabel=B;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("react/jsx-runtime"),t=require("react"),U=require("react-dom"),v=require("../../../utils/styles.cjs"),A=t.createContext(null);function F(){const w=t.useContext(A);if(!w)throw new Error("Dropdown components must be used within a Dropdown");return w}const P=t.forwardRef(function({trigger:o,isOpen:s,defaultOpen:a=!1,onOpenChange:d,placement:i="bottom-start",offset:D=4,closeOnSelect:y=!0,className:k,style:h,children:x,testId:g,...E},C){const[M,X]=t.useState(a),[N,Y]=t.useState({top:0,left:0}),[f,p]=t.useState(-1),[j,L]=t.useState(!1),m=t.useRef(null),b=t.useRef(null),n=s??M;t.useEffect(()=>(L(!0),()=>L(!1)),[]);const l=t.useCallback(e=>{s===void 0&&X(e),d?.(e),e||p(-1)},[s,d]),B=t.useCallback(()=>l(!1),[l]);t.useEffect(()=>{if(!n||!m.current||!j)return;const e=()=>{const r=m.current;if(!r)return;const u=r.getBoundingClientRect(),W=window.scrollX,q=window.scrollY;let R=0,I=0;i.startsWith("bottom")?R=u.bottom+q+D:R=u.top+q-D,i.endsWith("start")?I=u.left+W:I=u.right+W,Y({top:R,left:I})};return e(),window.addEventListener("resize",e),window.addEventListener("scroll",e,!0),()=>{window.removeEventListener("resize",e),window.removeEventListener("scroll",e,!0)}},[n,i,D,j]),t.useEffect(()=>{if(!n)return;const e=r=>{m.current?.contains(r.target)||b.current?.contains(r.target)||l(!1)};return document.addEventListener("mousedown",e),()=>document.removeEventListener("mousedown",e)},[n,l]);const S=t.useCallback(e=>{if(!n){(e.key==="ArrowDown"||e.key==="Enter"||e.key===" ")&&(e.preventDefault(),l(!0));return}const r=b.current?.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])');if(r?.length)switch(e.key){case"ArrowDown":e.preventDefault(),p(u=>(u+1)%r.length);break;case"ArrowUp":e.preventDefault(),p(u=>(u-1+r.length)%r.length);break;case"Home":e.preventDefault(),p(0);break;case"End":e.preventDefault(),p(r.length-1);break;case"Escape":e.preventDefault(),l(!1),m.current?.focus();break;case"Enter":case" ":e.preventDefault(),f>=0&&r[f]?.click();break}},[n,f,l]);t.useEffect(()=>{if(!n||f<0)return;b.current?.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')?.[f]?.focus()},[n,f]);const _=o.props,H=t.cloneElement(o,{ref:m,"aria-haspopup":"menu","aria-expanded":n,onClick:e=>{_.onClick?.(e),l(!n)},onKeyDown:e=>{_.onKeyDown?.(e),S(e)}}),T={position:"absolute",top:N.top,left:i.endsWith("end")?"auto":N.left,right:i.endsWith("end")?window.innerWidth-N.left:"auto",minWidth:m.current?.offsetWidth??160,...h};return c.jsx(A.Provider,{value:{isOpen:n,close:y?B:()=>{},activeIndex:f,setActiveIndex:p},children:c.jsxs("div",{ref:C,className:v.cx("brycks-dropdown",k),"data-testid":g,...E,children:[H,n&&j&&U.createPortal(c.jsx("div",{ref:b,role:"menu",className:"brycks-dropdown__menu",style:T,onKeyDown:S,tabIndex:-1,children:x}),document.body)]})})});P.displayName="Dropdown";const K=t.forwardRef(function({disabled:o=!1,icon:s,shortcut:a,destructive:d=!1,className:i,style:D,children:y,onClick:k,...h},x){const{close:g}=F(),E=C=>{o||(k?.(C),g())};return c.jsxs("div",{ref:x,role:"menuitem","aria-disabled":o,tabIndex:o?-1:0,className:v.cx("brycks-dropdown-item",o&&"brycks-dropdown-item--disabled",d&&"brycks-dropdown-item--destructive",i),style:D,onClick:E,...h,children:[s&&c.jsx("span",{className:"brycks-dropdown-item__icon",children:s}),c.jsx("span",{className:"brycks-dropdown-item__label",children:y}),a&&c.jsx("span",{className:"brycks-dropdown-item__shortcut",children:a})]})});K.displayName="DropdownItem";const O=t.forwardRef(function({className:o,style:s,...a},d){return c.jsx("div",{ref:d,role:"separator",className:v.cx("brycks-dropdown-divider",o),style:s,...a})});O.displayName="DropdownDivider";const z=t.forwardRef(function({className:o,style:s,children:a,...d},i){return c.jsx("div",{ref:i,className:v.cx("brycks-dropdown-label",o),style:s,...d,children:a})});z.displayName="DropdownLabel";exports.Dropdown=P;exports.DropdownDivider=O;exports.DropdownItem=K;exports.DropdownLabel=z;
|
|
7
2
|
//# sourceMappingURL=Dropdown.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dropdown.cjs","sources":["../../../../src/components/navigation/Dropdown/Dropdown.tsx"],"sourcesContent":["/**\n * Dropdown Component\n *\n * A dropdown menu with keyboard navigation support.\n * Can be used for actions, navigation, or selection.\n */\n\nimport {\n forwardRef,\n useState,\n useCallback,\n useRef,\n useEffect,\n cloneElement,\n createContext,\n useContext,\n type CSSProperties,\n type ReactNode,\n type ReactElement,\n type HTMLAttributes,\n type KeyboardEvent,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { cx } from '../../../utils/styles'\nimport { spacing, fontSizes, durations, easings } from '../../../design-system'\nimport { componentGap, componentPaddingX, componentPaddingY, iconSizes } from '../../../design-system/primitives'\n\nexport type DropdownPlacement = 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end'\n\ninterface DropdownContextValue {\n isOpen: boolean\n close: () => void\n activeIndex: number\n setActiveIndex: (index: number) => void\n}\n\nconst DropdownContext = createContext<DropdownContextValue | null>(null)\n\nfunction useDropdownContext() {\n const context = useContext(DropdownContext)\n if (!context) {\n throw new Error('Dropdown components must be used within a Dropdown')\n }\n return context\n}\n\nexport interface DropdownProps extends HTMLAttributes<HTMLDivElement> {\n /** Trigger element */\n trigger: ReactElement\n /** Whether the dropdown is open (controlled) */\n isOpen?: boolean\n /** Default open state (uncontrolled) */\n defaultOpen?: boolean\n /** Callback when open state changes */\n onOpenChange?: (isOpen: boolean) => void\n /** Dropdown placement */\n placement?: DropdownPlacement\n /** Offset from trigger */\n offset?: number\n /** Whether to close on item select */\n closeOnSelect?: boolean\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nexport const Dropdown = forwardRef<HTMLDivElement, DropdownProps>(function Dropdown(\n {\n trigger,\n isOpen: controlledIsOpen,\n defaultOpen = false,\n onOpenChange,\n placement = 'bottom-start',\n offset = 4,\n closeOnSelect = true,\n className,\n style,\n children,\n testId,\n ...props\n },\n ref\n) {\n const [internalIsOpen, setInternalIsOpen] = useState(defaultOpen)\n const [position, setPosition] = useState({ top: 0, left: 0 })\n const [activeIndex, setActiveIndex] = useState(-1)\n const [mounted, setMounted] = useState(false)\n const triggerRef = useRef<HTMLElement>(null)\n const menuRef = useRef<HTMLDivElement>(null)\n\n const isOpen = controlledIsOpen ?? internalIsOpen\n\n useEffect(() => {\n setMounted(true)\n return () => setMounted(false)\n }, [])\n\n const setIsOpen = useCallback(\n (open: boolean) => {\n if (controlledIsOpen === undefined) {\n setInternalIsOpen(open)\n }\n onOpenChange?.(open)\n if (!open) {\n setActiveIndex(-1)\n }\n },\n [controlledIsOpen, onOpenChange]\n )\n\n const close = useCallback(() => setIsOpen(false), [setIsOpen])\n\n // Calculate position\n useEffect(() => {\n if (!isOpen || !triggerRef.current || !mounted) return\n\n const updatePosition = () => {\n const trigger = triggerRef.current\n if (!trigger) return\n\n const rect = trigger.getBoundingClientRect()\n const scrollX = window.scrollX\n const scrollY = window.scrollY\n\n let top = 0\n let left = 0\n\n if (placement.startsWith('bottom')) {\n top = rect.bottom + scrollY + offset\n } else {\n top = rect.top + scrollY - offset\n }\n\n if (placement.endsWith('start')) {\n left = rect.left + scrollX\n } else {\n left = rect.right + scrollX\n }\n\n setPosition({ top, left })\n }\n\n updatePosition()\n window.addEventListener('resize', updatePosition)\n window.addEventListener('scroll', updatePosition, true)\n\n return () => {\n window.removeEventListener('resize', updatePosition)\n window.removeEventListener('scroll', updatePosition, true)\n }\n }, [isOpen, placement, offset, mounted])\n\n // Close on outside click\n useEffect(() => {\n if (!isOpen) return\n\n const handleClick = (e: MouseEvent) => {\n if (\n triggerRef.current?.contains(e.target as Node) ||\n menuRef.current?.contains(e.target as Node)\n ) {\n return\n }\n setIsOpen(false)\n }\n\n document.addEventListener('mousedown', handleClick)\n return () => document.removeEventListener('mousedown', handleClick)\n }, [isOpen, setIsOpen])\n\n // Keyboard navigation\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (!isOpen) {\n if (e.key === 'ArrowDown' || e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n setIsOpen(true)\n }\n return\n }\n\n const items = menuRef.current?.querySelectorAll<HTMLElement>('[role=\"menuitem\"]:not([aria-disabled=\"true\"])')\n if (!items?.length) return\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n setActiveIndex((prev) => (prev + 1) % items.length)\n break\n case 'ArrowUp':\n e.preventDefault()\n setActiveIndex((prev) => (prev - 1 + items.length) % items.length)\n break\n case 'Home':\n e.preventDefault()\n setActiveIndex(0)\n break\n case 'End':\n e.preventDefault()\n setActiveIndex(items.length - 1)\n break\n case 'Escape':\n e.preventDefault()\n setIsOpen(false)\n triggerRef.current?.focus()\n break\n case 'Enter':\n case ' ':\n e.preventDefault()\n if (activeIndex >= 0) {\n items[activeIndex]?.click()\n }\n break\n }\n },\n [isOpen, activeIndex, setIsOpen]\n )\n\n // Focus active item\n useEffect(() => {\n if (!isOpen || activeIndex < 0) return\n const items = menuRef.current?.querySelectorAll<HTMLElement>('[role=\"menuitem\"]:not([aria-disabled=\"true\"])')\n items?.[activeIndex]?.focus()\n }, [isOpen, activeIndex])\n\n const triggerProps = trigger.props as Record<string, unknown>\n const triggerElement = cloneElement(trigger as ReactElement<Record<string, unknown>>, {\n ref: triggerRef,\n 'aria-haspopup': 'menu',\n 'aria-expanded': isOpen,\n onClick: (e: React.MouseEvent) => {\n (triggerProps.onClick as ((e: React.MouseEvent) => void) | undefined)?.(e)\n setIsOpen(!isOpen)\n },\n onKeyDown: (e: KeyboardEvent) => {\n (triggerProps.onKeyDown as ((e: KeyboardEvent) => void) | undefined)?.(e)\n handleKeyDown(e)\n },\n })\n\n const menuStyle: CSSProperties = {\n position: 'absolute',\n top: position.top,\n left: placement.endsWith('end') ? 'auto' : position.left,\n right: placement.endsWith('end') ? window.innerWidth - position.left : 'auto',\n zIndex: 'var(--brycks-z-dropdown)' as unknown as number,\n minWidth: triggerRef.current?.offsetWidth ?? 160,\n backgroundColor: 'var(--brycks-background-elevated)',\n border: '1px solid var(--brycks-border-default)',\n borderRadius: 'var(--brycks-radius-lg)',\n boxShadow: 'var(--brycks-shadow-lg)',\n padding: spacing[1],\n animation: `brycks-dropdown-in ${durations.quick}ms ${easings.easeOut}`,\n outline: 'none',\n ...style,\n }\n\n return (\n <DropdownContext.Provider value={{ isOpen, close: closeOnSelect ? close : () => {}, activeIndex, setActiveIndex }}>\n <div\n ref={ref}\n className={cx('brycks-dropdown', className)}\n style={{ display: 'inline-block' }}\n data-testid={testId}\n {...props}\n >\n {triggerElement}\n {isOpen && mounted && createPortal(\n <>\n <style>\n {`\n @keyframes brycks-dropdown-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n }\n `}\n </style>\n <div\n ref={menuRef}\n role=\"menu\"\n style={menuStyle}\n onKeyDown={handleKeyDown}\n tabIndex={-1}\n >\n {children}\n </div>\n </>,\n document.body\n )}\n </div>\n </DropdownContext.Provider>\n )\n})\n\nDropdown.displayName = 'Dropdown'\n\n// DropdownItem\nexport interface DropdownItemProps extends HTMLAttributes<HTMLDivElement> {\n /** Whether the item is disabled */\n disabled?: boolean\n /** Icon before the label */\n icon?: ReactNode\n /** Shortcut text */\n shortcut?: string\n /** Whether the item is destructive */\n destructive?: boolean\n /** Custom class name */\n className?: string\n}\n\nexport const DropdownItem = forwardRef<HTMLDivElement, DropdownItemProps>(function DropdownItem(\n { disabled = false, icon, shortcut, destructive = false, className, style, children, onClick, ...props },\n ref\n) {\n const { close } = useDropdownContext()\n\n const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {\n if (disabled) return\n onClick?.(e)\n close()\n }\n\n const itemStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: componentGap.lg,\n padding: `${componentPaddingY.md}px ${componentPaddingX.sm}px`,\n fontSize: fontSizes.base,\n color: disabled\n ? 'var(--brycks-foreground-disabled)'\n : destructive\n ? 'var(--brycks-error-default)'\n : 'var(--brycks-foreground-default)',\n backgroundColor: 'transparent',\n borderRadius: 'var(--brycks-radius-md)',\n cursor: disabled ? 'not-allowed' : 'pointer',\n transition: `background-color ${durations.fast}ms ${easings.easeOut}`,\n outline: 'none',\n ...style,\n }\n\n const iconStyle: CSSProperties = {\n width: iconSizes.sm,\n height: iconSizes.sm,\n color: disabled\n ? 'var(--brycks-foreground-disabled)'\n : destructive\n ? 'var(--brycks-error-default)'\n : 'var(--brycks-foreground-muted)',\n flexShrink: 0,\n }\n\n const shortcutStyle: CSSProperties = {\n marginLeft: 'auto',\n fontSize: fontSizes.sm,\n color: 'var(--brycks-foreground-muted)',\n fontFamily: 'var(--brycks-font-mono)',\n }\n\n return (\n <div\n ref={ref}\n role=\"menuitem\"\n aria-disabled={disabled}\n tabIndex={disabled ? -1 : 0}\n className={cx('brycks-dropdown-item', disabled && 'brycks-dropdown-item--disabled', className)}\n style={itemStyle}\n onClick={handleClick}\n onMouseEnter={(e) => {\n if (!disabled) {\n e.currentTarget.style.backgroundColor = 'var(--brycks-background-muted)'\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent'\n }}\n onFocus={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--brycks-background-muted)'\n }}\n onBlur={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent'\n }}\n {...props}\n >\n {icon && <span style={iconStyle}>{icon}</span>}\n <span style={{ flex: 1 }}>{children}</span>\n {shortcut && <span style={shortcutStyle}>{shortcut}</span>}\n </div>\n )\n})\n\nDropdownItem.displayName = 'DropdownItem'\n\n// DropdownDivider\nexport interface DropdownDividerProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name */\n className?: string\n}\n\nexport const DropdownDivider = forwardRef<HTMLDivElement, DropdownDividerProps>(function DropdownDivider(\n { className, style, ...props },\n ref\n) {\n const dividerStyle: CSSProperties = {\n height: 1,\n backgroundColor: 'var(--brycks-border-muted)',\n margin: `${spacing[1]}px 0`,\n ...style,\n }\n\n return (\n <div\n ref={ref}\n role=\"separator\"\n className={cx('brycks-dropdown-divider', className)}\n style={dividerStyle}\n {...props}\n />\n )\n})\n\nDropdownDivider.displayName = 'DropdownDivider'\n\n// DropdownLabel\nexport interface DropdownLabelProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name */\n className?: string\n}\n\nexport const DropdownLabel = forwardRef<HTMLDivElement, DropdownLabelProps>(function DropdownLabel(\n { className, style, children, ...props },\n ref\n) {\n const labelStyle: CSSProperties = {\n padding: `${componentPaddingY.md}px ${componentPaddingX.sm}px ${spacing[1]}px ${componentPaddingX.sm}px`,\n fontSize: fontSizes.xs,\n fontWeight: 600,\n color: 'var(--brycks-foreground-muted)',\n textTransform: 'uppercase',\n letterSpacing: '0.05em',\n ...style,\n }\n\n return (\n <div\n ref={ref}\n className={cx('brycks-dropdown-label', className)}\n style={labelStyle}\n {...props}\n >\n {children}\n </div>\n )\n})\n\nDropdownLabel.displayName = 'DropdownLabel'\n"],"names":["DropdownContext","createContext","useDropdownContext","context","useContext","Dropdown","forwardRef","trigger","controlledIsOpen","defaultOpen","onOpenChange","placement","offset","closeOnSelect","className","style","children","testId","props","ref","internalIsOpen","setInternalIsOpen","useState","position","setPosition","activeIndex","setActiveIndex","mounted","setMounted","triggerRef","useRef","menuRef","isOpen","useEffect","setIsOpen","useCallback","open","close","updatePosition","rect","scrollX","scrollY","top","left","handleClick","e","handleKeyDown","items","prev","triggerProps","triggerElement","cloneElement","menuStyle","spacing","durations","easings","jsx","jsxs","cx","createPortal","Fragment","DropdownItem","disabled","icon","shortcut","destructive","onClick","itemStyle","componentGap","componentPaddingY","componentPaddingX","fontSizes","iconStyle","iconSizes","shortcutStyle","DropdownDivider","dividerStyle","DropdownLabel","labelStyle"],"mappings":"uaAoCMA,EAAkBC,EAAAA,cAA2C,IAAI,EAEvE,SAASC,GAAqB,CAC5B,MAAMC,EAAUC,EAAAA,WAAWJ,CAAe,EAC1C,GAAI,CAACG,EACH,MAAM,IAAI,MAAM,oDAAoD,EAEtE,OAAOA,CACT,CAuBO,MAAME,EAAWC,EAAAA,WAA0C,SAChE,CACE,QAAAC,EACA,OAAQC,EACR,YAAAC,EAAc,GACd,aAAAC,EACA,UAAAC,EAAY,eACZ,OAAAC,EAAS,EACT,cAAAC,EAAgB,GAChB,UAAAC,EACA,MAAAC,EACA,SAAAC,EACA,OAAAC,EACA,GAAGC,CACL,EACAC,EACA,CACA,KAAM,CAACC,EAAgBC,CAAiB,EAAIC,EAAAA,SAASb,CAAW,EAC1D,CAACc,EAAUC,CAAW,EAAIF,EAAAA,SAAS,CAAE,IAAK,EAAG,KAAM,EAAG,EACtD,CAACG,EAAaC,CAAc,EAAIJ,EAAAA,SAAS,EAAE,EAC3C,CAACK,EAASC,CAAU,EAAIN,EAAAA,SAAS,EAAK,EACtCO,EAAaC,EAAAA,OAAoB,IAAI,EACrCC,EAAUD,EAAAA,OAAuB,IAAI,EAErCE,EAASxB,GAAoBY,EAEnCa,EAAAA,UAAU,KACRL,EAAW,EAAI,EACR,IAAMA,EAAW,EAAK,GAC5B,CAAA,CAAE,EAEL,MAAMM,EAAYC,EAAAA,YACfC,GAAkB,CACb5B,IAAqB,QACvBa,EAAkBe,CAAI,EAExB1B,IAAe0B,CAAI,EACdA,GACHV,EAAe,EAAE,CAErB,EACA,CAAClB,EAAkBE,CAAY,CAAA,EAG3B2B,EAAQF,EAAAA,YAAY,IAAMD,EAAU,EAAK,EAAG,CAACA,CAAS,CAAC,EAG7DD,EAAAA,UAAU,IAAM,CACd,GAAI,CAACD,GAAU,CAACH,EAAW,SAAW,CAACF,EAAS,OAEhD,MAAMW,EAAiB,IAAM,CAC3B,MAAM/B,EAAUsB,EAAW,QAC3B,GAAI,CAACtB,EAAS,OAEd,MAAMgC,EAAOhC,EAAQ,sBAAA,EACfiC,EAAU,OAAO,QACjBC,EAAU,OAAO,QAEvB,IAAIC,EAAM,EACNC,EAAO,EAEPhC,EAAU,WAAW,QAAQ,EAC/B+B,EAAMH,EAAK,OAASE,EAAU7B,EAE9B8B,EAAMH,EAAK,IAAME,EAAU7B,EAGzBD,EAAU,SAAS,OAAO,EAC5BgC,EAAOJ,EAAK,KAAOC,EAEnBG,EAAOJ,EAAK,MAAQC,EAGtBhB,EAAY,CAAE,IAAAkB,EAAK,KAAAC,EAAM,CAC3B,EAEA,OAAAL,EAAA,EACA,OAAO,iBAAiB,SAAUA,CAAc,EAChD,OAAO,iBAAiB,SAAUA,EAAgB,EAAI,EAE/C,IAAM,CACX,OAAO,oBAAoB,SAAUA,CAAc,EACnD,OAAO,oBAAoB,SAAUA,EAAgB,EAAI,CAC3D,CACF,EAAG,CAACN,EAAQrB,EAAWC,EAAQe,CAAO,CAAC,EAGvCM,EAAAA,UAAU,IAAM,CACd,GAAI,CAACD,EAAQ,OAEb,MAAMY,EAAeC,GAAkB,CAEnChB,EAAW,SAAS,SAASgB,EAAE,MAAc,GAC7Cd,EAAQ,SAAS,SAASc,EAAE,MAAc,GAI5CX,EAAU,EAAK,CACjB,EAEA,gBAAS,iBAAiB,YAAaU,CAAW,EAC3C,IAAM,SAAS,oBAAoB,YAAaA,CAAW,CACpE,EAAG,CAACZ,EAAQE,CAAS,CAAC,EAGtB,MAAMY,EAAgBX,EAAAA,YACnB,GAAqB,CACpB,GAAI,CAACH,EAAQ,EACP,EAAE,MAAQ,aAAe,EAAE,MAAQ,SAAW,EAAE,MAAQ,OAC1D,EAAE,eAAA,EACFE,EAAU,EAAI,GAEhB,MACF,CAEA,MAAMa,EAAQhB,EAAQ,SAAS,iBAA8B,+CAA+C,EAC5G,GAAKgB,GAAO,OAEZ,OAAQ,EAAE,IAAA,CACR,IAAK,YACH,EAAE,eAAA,EACFrB,EAAgBsB,IAAUA,EAAO,GAAKD,EAAM,MAAM,EAClD,MACF,IAAK,UACH,EAAE,eAAA,EACFrB,EAAgBsB,IAAUA,EAAO,EAAID,EAAM,QAAUA,EAAM,MAAM,EACjE,MACF,IAAK,OACH,EAAE,eAAA,EACFrB,EAAe,CAAC,EAChB,MACF,IAAK,MACH,EAAE,eAAA,EACFA,EAAeqB,EAAM,OAAS,CAAC,EAC/B,MACF,IAAK,SACH,EAAE,eAAA,EACFb,EAAU,EAAK,EACfL,EAAW,SAAS,MAAA,EACpB,MACF,IAAK,QACL,IAAK,IACH,EAAE,eAAA,EACEJ,GAAe,GACjBsB,EAAMtB,CAAW,GAAG,MAAA,EAEtB,KAAA,CAEN,EACA,CAACO,EAAQP,EAAaS,CAAS,CAAA,EAIjCD,EAAAA,UAAU,IAAM,CACd,GAAI,CAACD,GAAUP,EAAc,EAAG,OAClBM,EAAQ,SAAS,iBAA8B,+CAA+C,IACpGN,CAAW,GAAG,MAAA,CACxB,EAAG,CAACO,EAAQP,CAAW,CAAC,EAExB,MAAMwB,EAAe1C,EAAQ,MACvB2C,EAAiBC,EAAAA,aAAa5C,EAAkD,CACpF,IAAKsB,EACL,gBAAiB,OACjB,gBAAiBG,EACjB,QAAU,GAAwB,CAC/BiB,EAAa,UAA0D,CAAC,EACzEf,EAAU,CAACF,CAAM,CACnB,EACA,UAAY,GAAqB,CAC9BiB,EAAa,YAAyD,CAAC,EACxEH,EAAc,CAAC,CACjB,CAAA,CACD,EAEKM,EAA2B,CAC/B,SAAU,WACV,IAAK7B,EAAS,IACd,KAAMZ,EAAU,SAAS,KAAK,EAAI,OAASY,EAAS,KACpD,MAAOZ,EAAU,SAAS,KAAK,EAAI,OAAO,WAAaY,EAAS,KAAO,OACvE,OAAQ,2BACR,SAAUM,EAAW,SAAS,aAAe,IAC7C,gBAAiB,oCACjB,OAAQ,yCACR,aAAc,0BACd,UAAW,0BACX,QAASwB,EAAAA,QAAQ,CAAC,EAClB,UAAW,sBAAsBC,EAAAA,UAAU,KAAK,MAAMC,EAAAA,QAAQ,OAAO,GACrE,QAAS,OACT,GAAGxC,CAAA,EAGL,OACEyC,EAAAA,IAACxD,EAAgB,SAAhB,CAAyB,MAAO,CAAE,OAAAgC,EAAQ,MAAOnB,EAAgBwB,EAAQ,IAAM,CAAC,EAAG,YAAAZ,EAAa,eAAAC,CAAA,EAC/F,SAAA+B,EAAAA,KAAC,MAAA,CACC,IAAAtC,EACA,UAAWuC,EAAAA,GAAG,kBAAmB5C,CAAS,EAC1C,MAAO,CAAE,QAAS,cAAA,EAClB,cAAaG,EACZ,GAAGC,EAEH,SAAA,CAAAgC,EACAlB,GAAUL,GAAWgC,EAAAA,aACpBF,OAAAG,EAAAA,SAAA,CACE,SAAA,CAAAJ,MAAC,QAAA,CACE,SAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAMH,EACAA,EAAAA,IAAC,MAAA,CACC,IAAKzB,EACL,KAAK,OACL,MAAOqB,EACP,UAAWN,EACX,SAAU,GAET,SAAA9B,CAAA,CAAA,CACH,EACF,EACA,SAAS,IAAA,CACX,CAAA,CAAA,EAEJ,CAEJ,CAAC,EAEDX,EAAS,YAAc,WAgBhB,MAAMwD,EAAevD,EAAAA,WAA8C,SACxE,CAAE,SAAAwD,EAAW,GAAO,KAAAC,EAAM,SAAAC,EAAU,YAAAC,EAAc,GAAO,UAAAnD,EAAW,MAAAC,EAAO,SAAAC,EAAU,QAAAkD,EAAS,GAAGhD,CAAA,EACjGC,EACA,CACA,KAAM,CAAE,MAAAkB,CAAA,EAAUnC,EAAA,EAEZ0C,EAAeC,GAAwC,CACvDiB,IACJI,IAAUrB,CAAC,EACXR,EAAA,EACF,EAEM8B,EAA2B,CAC/B,QAAS,OACT,WAAY,SACZ,IAAKC,EAAAA,aAAa,GAClB,QAAS,GAAGC,oBAAkB,EAAE,MAAMC,EAAAA,kBAAkB,EAAE,KAC1D,SAAUC,EAAAA,UAAU,KACpB,MAAOT,EACH,oCACAG,EACA,8BACA,mCACJ,gBAAiB,cACjB,aAAc,0BACd,OAAQH,EAAW,cAAgB,UACnC,WAAY,oBAAoBR,EAAAA,UAAU,IAAI,MAAMC,EAAAA,QAAQ,OAAO,GACnE,QAAS,OACT,GAAGxC,CAAA,EAGCyD,EAA2B,CAC/B,MAAOC,EAAAA,UAAU,GACjB,OAAQA,EAAAA,UAAU,GAClB,MAAOX,EACH,oCACAG,EACA,8BACA,iCACJ,WAAY,CAAA,EAGRS,EAA+B,CACnC,WAAY,OACZ,SAAUH,EAAAA,UAAU,GACpB,MAAO,iCACP,WAAY,yBAAA,EAGd,OACEd,EAAAA,KAAC,MAAA,CACC,IAAAtC,EACA,KAAK,WACL,gBAAe2C,EACf,SAAUA,EAAW,GAAK,EAC1B,UAAWJ,EAAAA,GAAG,uBAAwBI,GAAY,iCAAkChD,CAAS,EAC7F,MAAOqD,EACP,QAASvB,EACT,aAAeC,GAAM,CACdiB,IACHjB,EAAE,cAAc,MAAM,gBAAkB,iCAE5C,EACA,aAAeA,GAAM,CACnBA,EAAE,cAAc,MAAM,gBAAkB,aAC1C,EACA,QAAUA,GAAM,CACdA,EAAE,cAAc,MAAM,gBAAkB,gCAC1C,EACA,OAASA,GAAM,CACbA,EAAE,cAAc,MAAM,gBAAkB,aAC1C,EACC,GAAG3B,EAEH,SAAA,CAAA6C,GAAQP,EAAAA,IAAC,OAAA,CAAK,MAAOgB,EAAY,SAAAT,EAAK,QACtC,OAAA,CAAK,MAAO,CAAE,KAAM,CAAA,EAAM,SAAA/C,EAAS,EACnCgD,GAAYR,EAAAA,IAAC,OAAA,CAAK,MAAOkB,EAAgB,SAAAV,CAAA,CAAS,CAAA,CAAA,CAAA,CAGzD,CAAC,EAEDH,EAAa,YAAc,eAQpB,MAAMc,EAAkBrE,EAAAA,WAAiD,SAC9E,CAAE,UAAAQ,EAAW,MAAAC,EAAO,GAAGG,CAAA,EACvBC,EACA,CACA,MAAMyD,EAA8B,CAClC,OAAQ,EACR,gBAAiB,6BACjB,OAAQ,GAAGvB,EAAAA,QAAQ,CAAC,CAAC,OACrB,GAAGtC,CAAA,EAGL,OACEyC,EAAAA,IAAC,MAAA,CACC,IAAArC,EACA,KAAK,YACL,UAAWuC,EAAAA,GAAG,0BAA2B5C,CAAS,EAClD,MAAO8D,EACN,GAAG1D,CAAA,CAAA,CAGV,CAAC,EAEDyD,EAAgB,YAAc,kBAQvB,MAAME,EAAgBvE,EAAAA,WAA+C,SAC1E,CAAE,UAAAQ,EAAW,MAAAC,EAAO,SAAAC,EAAU,GAAGE,CAAA,EACjCC,EACA,CACA,MAAM2D,EAA4B,CAChC,QAAS,GAAGT,EAAAA,kBAAkB,EAAE,MAAMC,EAAAA,kBAAkB,EAAE,MAAMjB,EAAAA,QAAQ,CAAC,CAAC,MAAMiB,EAAAA,kBAAkB,EAAE,KACpG,SAAUC,EAAAA,UAAU,GACpB,WAAY,IACZ,MAAO,iCACP,cAAe,YACf,cAAe,SACf,GAAGxD,CAAA,EAGL,OACEyC,EAAAA,IAAC,MAAA,CACC,IAAArC,EACA,UAAWuC,EAAAA,GAAG,wBAAyB5C,CAAS,EAChD,MAAOgE,EACN,GAAG5D,EAEH,SAAAF,CAAA,CAAA,CAGP,CAAC,EAED6D,EAAc,YAAc"}
|
|
1
|
+
{"version":3,"file":"Dropdown.cjs","sources":["../../../../src/components/navigation/Dropdown/Dropdown.tsx"],"sourcesContent":["/**\n * Dropdown Component\n *\n * A dropdown menu with keyboard navigation support.\n * Can be used for actions, navigation, or selection.\n *\n * All color styles are handled via CSS classes for easy customization.\n */\n\nimport {\n forwardRef,\n useState,\n useCallback,\n useRef,\n useEffect,\n cloneElement,\n createContext,\n useContext,\n type CSSProperties,\n type ReactNode,\n type ReactElement,\n type HTMLAttributes,\n type KeyboardEvent,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { cx } from '../../../utils/styles'\n\nexport type DropdownPlacement = 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end'\n\ninterface DropdownContextValue {\n isOpen: boolean\n close: () => void\n activeIndex: number\n setActiveIndex: (index: number) => void\n}\n\nconst DropdownContext = createContext<DropdownContextValue | null>(null)\n\nfunction useDropdownContext() {\n const context = useContext(DropdownContext)\n if (!context) {\n throw new Error('Dropdown components must be used within a Dropdown')\n }\n return context\n}\n\nexport interface DropdownProps extends HTMLAttributes<HTMLDivElement> {\n /** Trigger element */\n trigger: ReactElement\n /** Whether the dropdown is open (controlled) */\n isOpen?: boolean\n /** Default open state (uncontrolled) */\n defaultOpen?: boolean\n /** Callback when open state changes */\n onOpenChange?: (isOpen: boolean) => void\n /** Dropdown placement */\n placement?: DropdownPlacement\n /** Offset from trigger */\n offset?: number\n /** Whether to close on item select */\n closeOnSelect?: boolean\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nexport const Dropdown = forwardRef<HTMLDivElement, DropdownProps>(function Dropdown(\n {\n trigger,\n isOpen: controlledIsOpen,\n defaultOpen = false,\n onOpenChange,\n placement = 'bottom-start',\n offset = 4,\n closeOnSelect = true,\n className,\n style,\n children,\n testId,\n ...props\n },\n ref\n) {\n const [internalIsOpen, setInternalIsOpen] = useState(defaultOpen)\n const [position, setPosition] = useState({ top: 0, left: 0 })\n const [activeIndex, setActiveIndex] = useState(-1)\n const [mounted, setMounted] = useState(false)\n const triggerRef = useRef<HTMLElement>(null)\n const menuRef = useRef<HTMLDivElement>(null)\n\n const isOpen = controlledIsOpen ?? internalIsOpen\n\n useEffect(() => {\n setMounted(true)\n return () => setMounted(false)\n }, [])\n\n const setIsOpen = useCallback(\n (open: boolean) => {\n if (controlledIsOpen === undefined) {\n setInternalIsOpen(open)\n }\n onOpenChange?.(open)\n if (!open) {\n setActiveIndex(-1)\n }\n },\n [controlledIsOpen, onOpenChange]\n )\n\n const close = useCallback(() => setIsOpen(false), [setIsOpen])\n\n // Calculate position\n useEffect(() => {\n if (!isOpen || !triggerRef.current || !mounted) return\n\n const updatePosition = () => {\n const trigger = triggerRef.current\n if (!trigger) return\n\n const rect = trigger.getBoundingClientRect()\n const scrollX = window.scrollX\n const scrollY = window.scrollY\n\n let top = 0\n let left = 0\n\n if (placement.startsWith('bottom')) {\n top = rect.bottom + scrollY + offset\n } else {\n top = rect.top + scrollY - offset\n }\n\n if (placement.endsWith('start')) {\n left = rect.left + scrollX\n } else {\n left = rect.right + scrollX\n }\n\n setPosition({ top, left })\n }\n\n updatePosition()\n window.addEventListener('resize', updatePosition)\n window.addEventListener('scroll', updatePosition, true)\n\n return () => {\n window.removeEventListener('resize', updatePosition)\n window.removeEventListener('scroll', updatePosition, true)\n }\n }, [isOpen, placement, offset, mounted])\n\n // Close on outside click\n useEffect(() => {\n if (!isOpen) return\n\n const handleClick = (e: MouseEvent) => {\n if (\n triggerRef.current?.contains(e.target as Node) ||\n menuRef.current?.contains(e.target as Node)\n ) {\n return\n }\n setIsOpen(false)\n }\n\n document.addEventListener('mousedown', handleClick)\n return () => document.removeEventListener('mousedown', handleClick)\n }, [isOpen, setIsOpen])\n\n // Keyboard navigation\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (!isOpen) {\n if (e.key === 'ArrowDown' || e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n setIsOpen(true)\n }\n return\n }\n\n const items = menuRef.current?.querySelectorAll<HTMLElement>('[role=\"menuitem\"]:not([aria-disabled=\"true\"])')\n if (!items?.length) return\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n setActiveIndex((prev) => (prev + 1) % items.length)\n break\n case 'ArrowUp':\n e.preventDefault()\n setActiveIndex((prev) => (prev - 1 + items.length) % items.length)\n break\n case 'Home':\n e.preventDefault()\n setActiveIndex(0)\n break\n case 'End':\n e.preventDefault()\n setActiveIndex(items.length - 1)\n break\n case 'Escape':\n e.preventDefault()\n setIsOpen(false)\n triggerRef.current?.focus()\n break\n case 'Enter':\n case ' ':\n e.preventDefault()\n if (activeIndex >= 0) {\n items[activeIndex]?.click()\n }\n break\n }\n },\n [isOpen, activeIndex, setIsOpen]\n )\n\n // Focus active item\n useEffect(() => {\n if (!isOpen || activeIndex < 0) return\n const items = menuRef.current?.querySelectorAll<HTMLElement>('[role=\"menuitem\"]:not([aria-disabled=\"true\"])')\n items?.[activeIndex]?.focus()\n }, [isOpen, activeIndex])\n\n const triggerProps = trigger.props as Record<string, unknown>\n const triggerElement = cloneElement(trigger as ReactElement<Record<string, unknown>>, {\n ref: triggerRef,\n 'aria-haspopup': 'menu',\n 'aria-expanded': isOpen,\n onClick: (e: React.MouseEvent) => {\n (triggerProps.onClick as ((e: React.MouseEvent) => void) | undefined)?.(e)\n setIsOpen(!isOpen)\n },\n onKeyDown: (e: KeyboardEvent) => {\n (triggerProps.onKeyDown as ((e: KeyboardEvent) => void) | undefined)?.(e)\n handleKeyDown(e)\n },\n })\n\n // Only layout-related inline styles (position is dynamic)\n const menuStyle: CSSProperties = {\n position: 'absolute',\n top: position.top,\n left: placement.endsWith('end') ? 'auto' : position.left,\n right: placement.endsWith('end') ? window.innerWidth - position.left : 'auto',\n minWidth: triggerRef.current?.offsetWidth ?? 160,\n ...style,\n }\n\n return (\n <DropdownContext.Provider value={{ isOpen, close: closeOnSelect ? close : () => {}, activeIndex, setActiveIndex }}>\n <div\n ref={ref}\n className={cx('brycks-dropdown', className)}\n data-testid={testId}\n {...props}\n >\n {triggerElement}\n {isOpen && mounted && createPortal(\n <div\n ref={menuRef}\n role=\"menu\"\n className=\"brycks-dropdown__menu\"\n style={menuStyle}\n onKeyDown={handleKeyDown}\n tabIndex={-1}\n >\n {children}\n </div>,\n document.body\n )}\n </div>\n </DropdownContext.Provider>\n )\n})\n\nDropdown.displayName = 'Dropdown'\n\n// DropdownItem\nexport interface DropdownItemProps extends HTMLAttributes<HTMLDivElement> {\n /** Whether the item is disabled */\n disabled?: boolean\n /** Icon before the label */\n icon?: ReactNode\n /** Shortcut text */\n shortcut?: string\n /** Whether the item is destructive */\n destructive?: boolean\n /** Custom class name */\n className?: string\n}\n\nexport const DropdownItem = forwardRef<HTMLDivElement, DropdownItemProps>(function DropdownItem(\n { disabled = false, icon, shortcut, destructive = false, className, style, children, onClick, ...props },\n ref\n) {\n const { close } = useDropdownContext()\n\n const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {\n if (disabled) return\n onClick?.(e)\n close()\n }\n\n return (\n <div\n ref={ref}\n role=\"menuitem\"\n aria-disabled={disabled}\n tabIndex={disabled ? -1 : 0}\n className={cx(\n 'brycks-dropdown-item',\n disabled && 'brycks-dropdown-item--disabled',\n destructive && 'brycks-dropdown-item--destructive',\n className\n )}\n style={style}\n onClick={handleClick}\n {...props}\n >\n {icon && <span className=\"brycks-dropdown-item__icon\">{icon}</span>}\n <span className=\"brycks-dropdown-item__label\">{children}</span>\n {shortcut && <span className=\"brycks-dropdown-item__shortcut\">{shortcut}</span>}\n </div>\n )\n})\n\nDropdownItem.displayName = 'DropdownItem'\n\n// DropdownDivider\nexport interface DropdownDividerProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name */\n className?: string\n}\n\nexport const DropdownDivider = forwardRef<HTMLDivElement, DropdownDividerProps>(function DropdownDivider(\n { className, style, ...props },\n ref\n) {\n return (\n <div\n ref={ref}\n role=\"separator\"\n className={cx('brycks-dropdown-divider', className)}\n style={style}\n {...props}\n />\n )\n})\n\nDropdownDivider.displayName = 'DropdownDivider'\n\n// DropdownLabel\nexport interface DropdownLabelProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name */\n className?: string\n}\n\nexport const DropdownLabel = forwardRef<HTMLDivElement, DropdownLabelProps>(function DropdownLabel(\n { className, style, children, ...props },\n ref\n) {\n return (\n <div\n ref={ref}\n className={cx('brycks-dropdown-label', className)}\n style={style}\n {...props}\n >\n {children}\n </div>\n )\n})\n\nDropdownLabel.displayName = 'DropdownLabel'\n"],"names":["DropdownContext","createContext","useDropdownContext","context","useContext","Dropdown","forwardRef","trigger","controlledIsOpen","defaultOpen","onOpenChange","placement","offset","closeOnSelect","className","style","children","testId","props","ref","internalIsOpen","setInternalIsOpen","useState","position","setPosition","activeIndex","setActiveIndex","mounted","setMounted","triggerRef","useRef","menuRef","isOpen","useEffect","setIsOpen","useCallback","open","close","updatePosition","rect","scrollX","scrollY","top","left","handleClick","e","handleKeyDown","items","prev","triggerProps","triggerElement","cloneElement","menuStyle","jsx","jsxs","cx","createPortal","DropdownItem","disabled","icon","shortcut","destructive","onClick","DropdownDivider","DropdownLabel"],"mappings":"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"}
|
|
@@ -1,263 +1,198 @@
|
|
|
1
|
-
import { jsx as u, jsxs as
|
|
2
|
-
import { forwardRef as
|
|
3
|
-
import { createPortal as
|
|
4
|
-
import { cx as
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const J = te(null);
|
|
10
|
-
function ae() {
|
|
11
|
-
const f = oe(J);
|
|
12
|
-
if (!f)
|
|
1
|
+
import { jsx as u, jsxs as O } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef as k, useState as b, useRef as z, useEffect as v, useCallback as P, cloneElement as G, createContext as J, useContext as Q } from "react";
|
|
3
|
+
import { createPortal as T } from "react-dom";
|
|
4
|
+
import { cx as y } from "../../../utils/styles.js";
|
|
5
|
+
const X = J(null);
|
|
6
|
+
function V() {
|
|
7
|
+
const p = Q(X);
|
|
8
|
+
if (!p)
|
|
13
9
|
throw new Error("Dropdown components must be used within a Dropdown");
|
|
14
|
-
return
|
|
10
|
+
return p;
|
|
15
11
|
}
|
|
16
|
-
const
|
|
12
|
+
const Z = k(function({
|
|
17
13
|
trigger: r,
|
|
18
|
-
isOpen:
|
|
19
|
-
defaultOpen:
|
|
20
|
-
onOpenChange:
|
|
14
|
+
isOpen: o,
|
|
15
|
+
defaultOpen: i = !1,
|
|
16
|
+
onOpenChange: c,
|
|
21
17
|
placement: s = "bottom-start",
|
|
22
|
-
offset:
|
|
23
|
-
closeOnSelect:
|
|
24
|
-
className:
|
|
25
|
-
style:
|
|
26
|
-
children:
|
|
27
|
-
testId:
|
|
28
|
-
...
|
|
29
|
-
},
|
|
30
|
-
const [
|
|
31
|
-
|
|
32
|
-
const
|
|
18
|
+
offset: f = 4,
|
|
19
|
+
closeOnSelect: h = !0,
|
|
20
|
+
className: g,
|
|
21
|
+
style: x,
|
|
22
|
+
children: E,
|
|
23
|
+
testId: N,
|
|
24
|
+
...C
|
|
25
|
+
}, I) {
|
|
26
|
+
const [Y, B] = b(i), [L, H] = b({ top: 0, left: 0 }), [l, m] = b(-1), [_, R] = b(!1), w = z(null), D = z(null), t = o ?? Y;
|
|
27
|
+
v(() => (R(!0), () => R(!1)), []);
|
|
28
|
+
const a = P(
|
|
33
29
|
(e) => {
|
|
34
|
-
|
|
30
|
+
o === void 0 && B(e), c?.(e), e || m(-1);
|
|
35
31
|
},
|
|
36
|
-
[
|
|
37
|
-
),
|
|
38
|
-
|
|
39
|
-
if (!
|
|
32
|
+
[o, c]
|
|
33
|
+
), M = P(() => a(!1), [a]);
|
|
34
|
+
v(() => {
|
|
35
|
+
if (!t || !w.current || !_) return;
|
|
40
36
|
const e = () => {
|
|
41
|
-
const n =
|
|
37
|
+
const n = w.current;
|
|
42
38
|
if (!n) return;
|
|
43
|
-
const
|
|
44
|
-
let W = 0,
|
|
45
|
-
s.startsWith("bottom") ? W =
|
|
39
|
+
const d = n.getBoundingClientRect(), j = window.scrollX, q = window.scrollY;
|
|
40
|
+
let W = 0, A = 0;
|
|
41
|
+
s.startsWith("bottom") ? W = d.bottom + q + f : W = d.top + q - f, s.endsWith("start") ? A = d.left + j : A = d.right + j, H({ top: W, left: A });
|
|
46
42
|
};
|
|
47
43
|
return e(), window.addEventListener("resize", e), window.addEventListener("scroll", e, !0), () => {
|
|
48
44
|
window.removeEventListener("resize", e), window.removeEventListener("scroll", e, !0);
|
|
49
45
|
};
|
|
50
|
-
}, [
|
|
51
|
-
if (!
|
|
46
|
+
}, [t, s, f, _]), v(() => {
|
|
47
|
+
if (!t) return;
|
|
52
48
|
const e = (n) => {
|
|
53
|
-
|
|
49
|
+
w.current?.contains(n.target) || D.current?.contains(n.target) || a(!1);
|
|
54
50
|
};
|
|
55
51
|
return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
|
|
56
|
-
}, [
|
|
57
|
-
const
|
|
52
|
+
}, [t, a]);
|
|
53
|
+
const K = P(
|
|
58
54
|
(e) => {
|
|
59
|
-
if (!
|
|
60
|
-
(e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") && (e.preventDefault(),
|
|
55
|
+
if (!t) {
|
|
56
|
+
(e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") && (e.preventDefault(), a(!0));
|
|
61
57
|
return;
|
|
62
58
|
}
|
|
63
|
-
const n =
|
|
59
|
+
const n = D.current?.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])');
|
|
64
60
|
if (n?.length)
|
|
65
61
|
switch (e.key) {
|
|
66
62
|
case "ArrowDown":
|
|
67
|
-
e.preventDefault(),
|
|
63
|
+
e.preventDefault(), m((d) => (d + 1) % n.length);
|
|
68
64
|
break;
|
|
69
65
|
case "ArrowUp":
|
|
70
|
-
e.preventDefault(),
|
|
66
|
+
e.preventDefault(), m((d) => (d - 1 + n.length) % n.length);
|
|
71
67
|
break;
|
|
72
68
|
case "Home":
|
|
73
|
-
e.preventDefault(),
|
|
69
|
+
e.preventDefault(), m(0);
|
|
74
70
|
break;
|
|
75
71
|
case "End":
|
|
76
|
-
e.preventDefault(),
|
|
72
|
+
e.preventDefault(), m(n.length - 1);
|
|
77
73
|
break;
|
|
78
74
|
case "Escape":
|
|
79
|
-
e.preventDefault(),
|
|
75
|
+
e.preventDefault(), a(!1), w.current?.focus();
|
|
80
76
|
break;
|
|
81
77
|
case "Enter":
|
|
82
78
|
case " ":
|
|
83
|
-
e.preventDefault(),
|
|
79
|
+
e.preventDefault(), l >= 0 && n[l]?.click();
|
|
84
80
|
break;
|
|
85
81
|
}
|
|
86
82
|
},
|
|
87
|
-
[
|
|
83
|
+
[t, l, a]
|
|
88
84
|
);
|
|
89
|
-
|
|
90
|
-
if (!
|
|
91
|
-
|
|
92
|
-
}, [
|
|
93
|
-
const
|
|
94
|
-
ref:
|
|
85
|
+
v(() => {
|
|
86
|
+
if (!t || l < 0) return;
|
|
87
|
+
D.current?.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')?.[l]?.focus();
|
|
88
|
+
}, [t, l]);
|
|
89
|
+
const S = r.props, U = G(r, {
|
|
90
|
+
ref: w,
|
|
95
91
|
"aria-haspopup": "menu",
|
|
96
|
-
"aria-expanded":
|
|
92
|
+
"aria-expanded": t,
|
|
97
93
|
onClick: (e) => {
|
|
98
|
-
|
|
94
|
+
S.onClick?.(e), a(!t);
|
|
99
95
|
},
|
|
100
96
|
onKeyDown: (e) => {
|
|
101
|
-
|
|
97
|
+
S.onKeyDown?.(e), K(e);
|
|
102
98
|
}
|
|
103
|
-
}),
|
|
99
|
+
}), F = {
|
|
104
100
|
position: "absolute",
|
|
105
|
-
top:
|
|
106
|
-
left: s.endsWith("end") ? "auto" :
|
|
107
|
-
right: s.endsWith("end") ? window.innerWidth -
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
backgroundColor: "var(--brycks-background-elevated)",
|
|
111
|
-
border: "1px solid var(--brycks-border-default)",
|
|
112
|
-
borderRadius: "var(--brycks-radius-lg)",
|
|
113
|
-
boxShadow: "var(--brycks-shadow-lg)",
|
|
114
|
-
padding: K[1],
|
|
115
|
-
animation: `brycks-dropdown-in ${H.quick}ms ${U.easeOut}`,
|
|
116
|
-
outline: "none",
|
|
117
|
-
...C
|
|
101
|
+
top: L.top,
|
|
102
|
+
left: s.endsWith("end") ? "auto" : L.left,
|
|
103
|
+
right: s.endsWith("end") ? window.innerWidth - L.left : "auto",
|
|
104
|
+
minWidth: w.current?.offsetWidth ?? 160,
|
|
105
|
+
...x
|
|
118
106
|
};
|
|
119
|
-
return /* @__PURE__ */ u(
|
|
120
|
-
}, activeIndex:
|
|
107
|
+
return /* @__PURE__ */ u(X.Provider, { value: { isOpen: t, close: h ? M : () => {
|
|
108
|
+
}, activeIndex: l, setActiveIndex: m }, children: /* @__PURE__ */ O(
|
|
121
109
|
"div",
|
|
122
110
|
{
|
|
123
|
-
ref:
|
|
124
|
-
className:
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
...I,
|
|
111
|
+
ref: I,
|
|
112
|
+
className: y("brycks-dropdown", g),
|
|
113
|
+
"data-testid": N,
|
|
114
|
+
...C,
|
|
128
115
|
children: [
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
/* @__PURE__ */
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
style: _,
|
|
144
|
-
onKeyDown: q,
|
|
145
|
-
tabIndex: -1,
|
|
146
|
-
children: S
|
|
147
|
-
}
|
|
148
|
-
)
|
|
149
|
-
] }),
|
|
116
|
+
U,
|
|
117
|
+
t && _ && T(
|
|
118
|
+
/* @__PURE__ */ u(
|
|
119
|
+
"div",
|
|
120
|
+
{
|
|
121
|
+
ref: D,
|
|
122
|
+
role: "menu",
|
|
123
|
+
className: "brycks-dropdown__menu",
|
|
124
|
+
style: F,
|
|
125
|
+
onKeyDown: K,
|
|
126
|
+
tabIndex: -1,
|
|
127
|
+
children: E
|
|
128
|
+
}
|
|
129
|
+
),
|
|
150
130
|
document.body
|
|
151
131
|
)
|
|
152
132
|
]
|
|
153
133
|
}
|
|
154
134
|
) });
|
|
155
135
|
});
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
const { close:
|
|
159
|
-
r || (
|
|
160
|
-
}, L = {
|
|
161
|
-
display: "flex",
|
|
162
|
-
alignItems: "center",
|
|
163
|
-
gap: se.lg,
|
|
164
|
-
padding: `${G.md}px ${T.sm}px`,
|
|
165
|
-
fontSize: Y.base,
|
|
166
|
-
color: r ? "var(--brycks-foreground-disabled)" : i ? "var(--brycks-error-default)" : "var(--brycks-foreground-default)",
|
|
167
|
-
backgroundColor: "transparent",
|
|
168
|
-
borderRadius: "var(--brycks-radius-md)",
|
|
169
|
-
cursor: r ? "not-allowed" : "pointer",
|
|
170
|
-
transition: `background-color ${H.fast}ms ${U.easeOut}`,
|
|
171
|
-
outline: "none",
|
|
172
|
-
...p
|
|
173
|
-
}, $ = {
|
|
174
|
-
width: B.sm,
|
|
175
|
-
height: B.sm,
|
|
176
|
-
color: r ? "var(--brycks-foreground-disabled)" : i ? "var(--brycks-error-default)" : "var(--brycks-foreground-muted)",
|
|
177
|
-
flexShrink: 0
|
|
178
|
-
}, z = {
|
|
179
|
-
marginLeft: "auto",
|
|
180
|
-
fontSize: Y.sm,
|
|
181
|
-
color: "var(--brycks-foreground-muted)",
|
|
182
|
-
fontFamily: "var(--brycks-font-mono)"
|
|
136
|
+
Z.displayName = "Dropdown";
|
|
137
|
+
const $ = k(function({ disabled: r = !1, icon: o, shortcut: i, destructive: c = !1, className: s, style: f, children: h, onClick: g, ...x }, E) {
|
|
138
|
+
const { close: N } = V(), C = (I) => {
|
|
139
|
+
r || (g?.(I), N());
|
|
183
140
|
};
|
|
184
|
-
return /* @__PURE__ */
|
|
141
|
+
return /* @__PURE__ */ O(
|
|
185
142
|
"div",
|
|
186
143
|
{
|
|
187
|
-
ref:
|
|
144
|
+
ref: E,
|
|
188
145
|
role: "menuitem",
|
|
189
146
|
"aria-disabled": r,
|
|
190
147
|
tabIndex: r ? -1 : 0,
|
|
191
|
-
className:
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
onFocus: (t) => {
|
|
201
|
-
t.currentTarget.style.backgroundColor = "var(--brycks-background-muted)";
|
|
202
|
-
},
|
|
203
|
-
onBlur: (t) => {
|
|
204
|
-
t.currentTarget.style.backgroundColor = "transparent";
|
|
205
|
-
},
|
|
206
|
-
...C,
|
|
148
|
+
className: y(
|
|
149
|
+
"brycks-dropdown-item",
|
|
150
|
+
r && "brycks-dropdown-item--disabled",
|
|
151
|
+
c && "brycks-dropdown-item--destructive",
|
|
152
|
+
s
|
|
153
|
+
),
|
|
154
|
+
style: f,
|
|
155
|
+
onClick: C,
|
|
156
|
+
...x,
|
|
207
157
|
children: [
|
|
208
|
-
|
|
209
|
-
/* @__PURE__ */ u("span", {
|
|
210
|
-
|
|
158
|
+
o && /* @__PURE__ */ u("span", { className: "brycks-dropdown-item__icon", children: o }),
|
|
159
|
+
/* @__PURE__ */ u("span", { className: "brycks-dropdown-item__label", children: h }),
|
|
160
|
+
i && /* @__PURE__ */ u("span", { className: "brycks-dropdown-item__shortcut", children: i })
|
|
211
161
|
]
|
|
212
162
|
}
|
|
213
163
|
);
|
|
214
164
|
});
|
|
215
|
-
|
|
216
|
-
const
|
|
217
|
-
const s = {
|
|
218
|
-
height: 1,
|
|
219
|
-
backgroundColor: "var(--brycks-border-muted)",
|
|
220
|
-
margin: `${K[1]}px 0`,
|
|
221
|
-
...a
|
|
222
|
-
};
|
|
165
|
+
$.displayName = "DropdownItem";
|
|
166
|
+
const ee = k(function({ className: r, style: o, ...i }, c) {
|
|
223
167
|
return /* @__PURE__ */ u(
|
|
224
168
|
"div",
|
|
225
169
|
{
|
|
226
|
-
ref:
|
|
170
|
+
ref: c,
|
|
227
171
|
role: "separator",
|
|
228
|
-
className:
|
|
229
|
-
style:
|
|
230
|
-
...
|
|
172
|
+
className: y("brycks-dropdown-divider", r),
|
|
173
|
+
style: o,
|
|
174
|
+
...i
|
|
231
175
|
}
|
|
232
176
|
);
|
|
233
177
|
});
|
|
234
|
-
|
|
235
|
-
const
|
|
236
|
-
const p = {
|
|
237
|
-
padding: `${G.md}px ${T.sm}px ${K[1]}px ${T.sm}px`,
|
|
238
|
-
fontSize: Y.xs,
|
|
239
|
-
fontWeight: 600,
|
|
240
|
-
color: "var(--brycks-foreground-muted)",
|
|
241
|
-
textTransform: "uppercase",
|
|
242
|
-
letterSpacing: "0.05em",
|
|
243
|
-
...a
|
|
244
|
-
};
|
|
178
|
+
ee.displayName = "DropdownDivider";
|
|
179
|
+
const te = k(function({ className: r, style: o, children: i, ...c }, s) {
|
|
245
180
|
return /* @__PURE__ */ u(
|
|
246
181
|
"div",
|
|
247
182
|
{
|
|
248
183
|
ref: s,
|
|
249
|
-
className:
|
|
250
|
-
style:
|
|
251
|
-
...
|
|
252
|
-
children:
|
|
184
|
+
className: y("brycks-dropdown-label", r),
|
|
185
|
+
style: o,
|
|
186
|
+
...c,
|
|
187
|
+
children: i
|
|
253
188
|
}
|
|
254
189
|
);
|
|
255
190
|
});
|
|
256
|
-
|
|
191
|
+
te.displayName = "DropdownLabel";
|
|
257
192
|
export {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
193
|
+
Z as Dropdown,
|
|
194
|
+
ee as DropdownDivider,
|
|
195
|
+
$ as DropdownItem,
|
|
196
|
+
te as DropdownLabel
|
|
262
197
|
};
|
|
263
198
|
//# sourceMappingURL=Dropdown.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dropdown.js","sources":["../../../../src/components/navigation/Dropdown/Dropdown.tsx"],"sourcesContent":["/**\n * Dropdown Component\n *\n * A dropdown menu with keyboard navigation support.\n * Can be used for actions, navigation, or selection.\n */\n\nimport {\n forwardRef,\n useState,\n useCallback,\n useRef,\n useEffect,\n cloneElement,\n createContext,\n useContext,\n type CSSProperties,\n type ReactNode,\n type ReactElement,\n type HTMLAttributes,\n type KeyboardEvent,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { cx } from '../../../utils/styles'\nimport { spacing, fontSizes, durations, easings } from '../../../design-system'\nimport { componentGap, componentPaddingX, componentPaddingY, iconSizes } from '../../../design-system/primitives'\n\nexport type DropdownPlacement = 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end'\n\ninterface DropdownContextValue {\n isOpen: boolean\n close: () => void\n activeIndex: number\n setActiveIndex: (index: number) => void\n}\n\nconst DropdownContext = createContext<DropdownContextValue | null>(null)\n\nfunction useDropdownContext() {\n const context = useContext(DropdownContext)\n if (!context) {\n throw new Error('Dropdown components must be used within a Dropdown')\n }\n return context\n}\n\nexport interface DropdownProps extends HTMLAttributes<HTMLDivElement> {\n /** Trigger element */\n trigger: ReactElement\n /** Whether the dropdown is open (controlled) */\n isOpen?: boolean\n /** Default open state (uncontrolled) */\n defaultOpen?: boolean\n /** Callback when open state changes */\n onOpenChange?: (isOpen: boolean) => void\n /** Dropdown placement */\n placement?: DropdownPlacement\n /** Offset from trigger */\n offset?: number\n /** Whether to close on item select */\n closeOnSelect?: boolean\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nexport const Dropdown = forwardRef<HTMLDivElement, DropdownProps>(function Dropdown(\n {\n trigger,\n isOpen: controlledIsOpen,\n defaultOpen = false,\n onOpenChange,\n placement = 'bottom-start',\n offset = 4,\n closeOnSelect = true,\n className,\n style,\n children,\n testId,\n ...props\n },\n ref\n) {\n const [internalIsOpen, setInternalIsOpen] = useState(defaultOpen)\n const [position, setPosition] = useState({ top: 0, left: 0 })\n const [activeIndex, setActiveIndex] = useState(-1)\n const [mounted, setMounted] = useState(false)\n const triggerRef = useRef<HTMLElement>(null)\n const menuRef = useRef<HTMLDivElement>(null)\n\n const isOpen = controlledIsOpen ?? internalIsOpen\n\n useEffect(() => {\n setMounted(true)\n return () => setMounted(false)\n }, [])\n\n const setIsOpen = useCallback(\n (open: boolean) => {\n if (controlledIsOpen === undefined) {\n setInternalIsOpen(open)\n }\n onOpenChange?.(open)\n if (!open) {\n setActiveIndex(-1)\n }\n },\n [controlledIsOpen, onOpenChange]\n )\n\n const close = useCallback(() => setIsOpen(false), [setIsOpen])\n\n // Calculate position\n useEffect(() => {\n if (!isOpen || !triggerRef.current || !mounted) return\n\n const updatePosition = () => {\n const trigger = triggerRef.current\n if (!trigger) return\n\n const rect = trigger.getBoundingClientRect()\n const scrollX = window.scrollX\n const scrollY = window.scrollY\n\n let top = 0\n let left = 0\n\n if (placement.startsWith('bottom')) {\n top = rect.bottom + scrollY + offset\n } else {\n top = rect.top + scrollY - offset\n }\n\n if (placement.endsWith('start')) {\n left = rect.left + scrollX\n } else {\n left = rect.right + scrollX\n }\n\n setPosition({ top, left })\n }\n\n updatePosition()\n window.addEventListener('resize', updatePosition)\n window.addEventListener('scroll', updatePosition, true)\n\n return () => {\n window.removeEventListener('resize', updatePosition)\n window.removeEventListener('scroll', updatePosition, true)\n }\n }, [isOpen, placement, offset, mounted])\n\n // Close on outside click\n useEffect(() => {\n if (!isOpen) return\n\n const handleClick = (e: MouseEvent) => {\n if (\n triggerRef.current?.contains(e.target as Node) ||\n menuRef.current?.contains(e.target as Node)\n ) {\n return\n }\n setIsOpen(false)\n }\n\n document.addEventListener('mousedown', handleClick)\n return () => document.removeEventListener('mousedown', handleClick)\n }, [isOpen, setIsOpen])\n\n // Keyboard navigation\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (!isOpen) {\n if (e.key === 'ArrowDown' || e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n setIsOpen(true)\n }\n return\n }\n\n const items = menuRef.current?.querySelectorAll<HTMLElement>('[role=\"menuitem\"]:not([aria-disabled=\"true\"])')\n if (!items?.length) return\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n setActiveIndex((prev) => (prev + 1) % items.length)\n break\n case 'ArrowUp':\n e.preventDefault()\n setActiveIndex((prev) => (prev - 1 + items.length) % items.length)\n break\n case 'Home':\n e.preventDefault()\n setActiveIndex(0)\n break\n case 'End':\n e.preventDefault()\n setActiveIndex(items.length - 1)\n break\n case 'Escape':\n e.preventDefault()\n setIsOpen(false)\n triggerRef.current?.focus()\n break\n case 'Enter':\n case ' ':\n e.preventDefault()\n if (activeIndex >= 0) {\n items[activeIndex]?.click()\n }\n break\n }\n },\n [isOpen, activeIndex, setIsOpen]\n )\n\n // Focus active item\n useEffect(() => {\n if (!isOpen || activeIndex < 0) return\n const items = menuRef.current?.querySelectorAll<HTMLElement>('[role=\"menuitem\"]:not([aria-disabled=\"true\"])')\n items?.[activeIndex]?.focus()\n }, [isOpen, activeIndex])\n\n const triggerProps = trigger.props as Record<string, unknown>\n const triggerElement = cloneElement(trigger as ReactElement<Record<string, unknown>>, {\n ref: triggerRef,\n 'aria-haspopup': 'menu',\n 'aria-expanded': isOpen,\n onClick: (e: React.MouseEvent) => {\n (triggerProps.onClick as ((e: React.MouseEvent) => void) | undefined)?.(e)\n setIsOpen(!isOpen)\n },\n onKeyDown: (e: KeyboardEvent) => {\n (triggerProps.onKeyDown as ((e: KeyboardEvent) => void) | undefined)?.(e)\n handleKeyDown(e)\n },\n })\n\n const menuStyle: CSSProperties = {\n position: 'absolute',\n top: position.top,\n left: placement.endsWith('end') ? 'auto' : position.left,\n right: placement.endsWith('end') ? window.innerWidth - position.left : 'auto',\n zIndex: 'var(--brycks-z-dropdown)' as unknown as number,\n minWidth: triggerRef.current?.offsetWidth ?? 160,\n backgroundColor: 'var(--brycks-background-elevated)',\n border: '1px solid var(--brycks-border-default)',\n borderRadius: 'var(--brycks-radius-lg)',\n boxShadow: 'var(--brycks-shadow-lg)',\n padding: spacing[1],\n animation: `brycks-dropdown-in ${durations.quick}ms ${easings.easeOut}`,\n outline: 'none',\n ...style,\n }\n\n return (\n <DropdownContext.Provider value={{ isOpen, close: closeOnSelect ? close : () => {}, activeIndex, setActiveIndex }}>\n <div\n ref={ref}\n className={cx('brycks-dropdown', className)}\n style={{ display: 'inline-block' }}\n data-testid={testId}\n {...props}\n >\n {triggerElement}\n {isOpen && mounted && createPortal(\n <>\n <style>\n {`\n @keyframes brycks-dropdown-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n }\n `}\n </style>\n <div\n ref={menuRef}\n role=\"menu\"\n style={menuStyle}\n onKeyDown={handleKeyDown}\n tabIndex={-1}\n >\n {children}\n </div>\n </>,\n document.body\n )}\n </div>\n </DropdownContext.Provider>\n )\n})\n\nDropdown.displayName = 'Dropdown'\n\n// DropdownItem\nexport interface DropdownItemProps extends HTMLAttributes<HTMLDivElement> {\n /** Whether the item is disabled */\n disabled?: boolean\n /** Icon before the label */\n icon?: ReactNode\n /** Shortcut text */\n shortcut?: string\n /** Whether the item is destructive */\n destructive?: boolean\n /** Custom class name */\n className?: string\n}\n\nexport const DropdownItem = forwardRef<HTMLDivElement, DropdownItemProps>(function DropdownItem(\n { disabled = false, icon, shortcut, destructive = false, className, style, children, onClick, ...props },\n ref\n) {\n const { close } = useDropdownContext()\n\n const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {\n if (disabled) return\n onClick?.(e)\n close()\n }\n\n const itemStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: componentGap.lg,\n padding: `${componentPaddingY.md}px ${componentPaddingX.sm}px`,\n fontSize: fontSizes.base,\n color: disabled\n ? 'var(--brycks-foreground-disabled)'\n : destructive\n ? 'var(--brycks-error-default)'\n : 'var(--brycks-foreground-default)',\n backgroundColor: 'transparent',\n borderRadius: 'var(--brycks-radius-md)',\n cursor: disabled ? 'not-allowed' : 'pointer',\n transition: `background-color ${durations.fast}ms ${easings.easeOut}`,\n outline: 'none',\n ...style,\n }\n\n const iconStyle: CSSProperties = {\n width: iconSizes.sm,\n height: iconSizes.sm,\n color: disabled\n ? 'var(--brycks-foreground-disabled)'\n : destructive\n ? 'var(--brycks-error-default)'\n : 'var(--brycks-foreground-muted)',\n flexShrink: 0,\n }\n\n const shortcutStyle: CSSProperties = {\n marginLeft: 'auto',\n fontSize: fontSizes.sm,\n color: 'var(--brycks-foreground-muted)',\n fontFamily: 'var(--brycks-font-mono)',\n }\n\n return (\n <div\n ref={ref}\n role=\"menuitem\"\n aria-disabled={disabled}\n tabIndex={disabled ? -1 : 0}\n className={cx('brycks-dropdown-item', disabled && 'brycks-dropdown-item--disabled', className)}\n style={itemStyle}\n onClick={handleClick}\n onMouseEnter={(e) => {\n if (!disabled) {\n e.currentTarget.style.backgroundColor = 'var(--brycks-background-muted)'\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent'\n }}\n onFocus={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--brycks-background-muted)'\n }}\n onBlur={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent'\n }}\n {...props}\n >\n {icon && <span style={iconStyle}>{icon}</span>}\n <span style={{ flex: 1 }}>{children}</span>\n {shortcut && <span style={shortcutStyle}>{shortcut}</span>}\n </div>\n )\n})\n\nDropdownItem.displayName = 'DropdownItem'\n\n// DropdownDivider\nexport interface DropdownDividerProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name */\n className?: string\n}\n\nexport const DropdownDivider = forwardRef<HTMLDivElement, DropdownDividerProps>(function DropdownDivider(\n { className, style, ...props },\n ref\n) {\n const dividerStyle: CSSProperties = {\n height: 1,\n backgroundColor: 'var(--brycks-border-muted)',\n margin: `${spacing[1]}px 0`,\n ...style,\n }\n\n return (\n <div\n ref={ref}\n role=\"separator\"\n className={cx('brycks-dropdown-divider', className)}\n style={dividerStyle}\n {...props}\n />\n )\n})\n\nDropdownDivider.displayName = 'DropdownDivider'\n\n// DropdownLabel\nexport interface DropdownLabelProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name */\n className?: string\n}\n\nexport const DropdownLabel = forwardRef<HTMLDivElement, DropdownLabelProps>(function DropdownLabel(\n { className, style, children, ...props },\n ref\n) {\n const labelStyle: CSSProperties = {\n padding: `${componentPaddingY.md}px ${componentPaddingX.sm}px ${spacing[1]}px ${componentPaddingX.sm}px`,\n fontSize: fontSizes.xs,\n fontWeight: 600,\n color: 'var(--brycks-foreground-muted)',\n textTransform: 'uppercase',\n letterSpacing: '0.05em',\n ...style,\n }\n\n return (\n <div\n ref={ref}\n className={cx('brycks-dropdown-label', className)}\n style={labelStyle}\n {...props}\n >\n {children}\n </div>\n )\n})\n\nDropdownLabel.displayName = 'DropdownLabel'\n"],"names":["DropdownContext","createContext","useDropdownContext","context","useContext","Dropdown","forwardRef","trigger","controlledIsOpen","defaultOpen","onOpenChange","placement","offset","closeOnSelect","className","style","children","testId","props","ref","internalIsOpen","setInternalIsOpen","useState","position","setPosition","activeIndex","setActiveIndex","mounted","setMounted","triggerRef","useRef","menuRef","isOpen","useEffect","setIsOpen","useCallback","open","close","updatePosition","rect","scrollX","scrollY","top","left","handleClick","e","handleKeyDown","items","prev","triggerProps","triggerElement","cloneElement","menuStyle","spacing","durations","easings","jsx","jsxs","cx","createPortal","Fragment","DropdownItem","disabled","icon","shortcut","destructive","onClick","itemStyle","componentGap","componentPaddingY","componentPaddingX","fontSizes","iconStyle","iconSizes","shortcutStyle","DropdownDivider","dividerStyle","DropdownLabel","labelStyle"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Dropdown.js","sources":["../../../../src/components/navigation/Dropdown/Dropdown.tsx"],"sourcesContent":["/**\n * Dropdown Component\n *\n * A dropdown menu with keyboard navigation support.\n * Can be used for actions, navigation, or selection.\n *\n * All color styles are handled via CSS classes for easy customization.\n */\n\nimport {\n forwardRef,\n useState,\n useCallback,\n useRef,\n useEffect,\n cloneElement,\n createContext,\n useContext,\n type CSSProperties,\n type ReactNode,\n type ReactElement,\n type HTMLAttributes,\n type KeyboardEvent,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { cx } from '../../../utils/styles'\n\nexport type DropdownPlacement = 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end'\n\ninterface DropdownContextValue {\n isOpen: boolean\n close: () => void\n activeIndex: number\n setActiveIndex: (index: number) => void\n}\n\nconst DropdownContext = createContext<DropdownContextValue | null>(null)\n\nfunction useDropdownContext() {\n const context = useContext(DropdownContext)\n if (!context) {\n throw new Error('Dropdown components must be used within a Dropdown')\n }\n return context\n}\n\nexport interface DropdownProps extends HTMLAttributes<HTMLDivElement> {\n /** Trigger element */\n trigger: ReactElement\n /** Whether the dropdown is open (controlled) */\n isOpen?: boolean\n /** Default open state (uncontrolled) */\n defaultOpen?: boolean\n /** Callback when open state changes */\n onOpenChange?: (isOpen: boolean) => void\n /** Dropdown placement */\n placement?: DropdownPlacement\n /** Offset from trigger */\n offset?: number\n /** Whether to close on item select */\n closeOnSelect?: boolean\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nexport const Dropdown = forwardRef<HTMLDivElement, DropdownProps>(function Dropdown(\n {\n trigger,\n isOpen: controlledIsOpen,\n defaultOpen = false,\n onOpenChange,\n placement = 'bottom-start',\n offset = 4,\n closeOnSelect = true,\n className,\n style,\n children,\n testId,\n ...props\n },\n ref\n) {\n const [internalIsOpen, setInternalIsOpen] = useState(defaultOpen)\n const [position, setPosition] = useState({ top: 0, left: 0 })\n const [activeIndex, setActiveIndex] = useState(-1)\n const [mounted, setMounted] = useState(false)\n const triggerRef = useRef<HTMLElement>(null)\n const menuRef = useRef<HTMLDivElement>(null)\n\n const isOpen = controlledIsOpen ?? internalIsOpen\n\n useEffect(() => {\n setMounted(true)\n return () => setMounted(false)\n }, [])\n\n const setIsOpen = useCallback(\n (open: boolean) => {\n if (controlledIsOpen === undefined) {\n setInternalIsOpen(open)\n }\n onOpenChange?.(open)\n if (!open) {\n setActiveIndex(-1)\n }\n },\n [controlledIsOpen, onOpenChange]\n )\n\n const close = useCallback(() => setIsOpen(false), [setIsOpen])\n\n // Calculate position\n useEffect(() => {\n if (!isOpen || !triggerRef.current || !mounted) return\n\n const updatePosition = () => {\n const trigger = triggerRef.current\n if (!trigger) return\n\n const rect = trigger.getBoundingClientRect()\n const scrollX = window.scrollX\n const scrollY = window.scrollY\n\n let top = 0\n let left = 0\n\n if (placement.startsWith('bottom')) {\n top = rect.bottom + scrollY + offset\n } else {\n top = rect.top + scrollY - offset\n }\n\n if (placement.endsWith('start')) {\n left = rect.left + scrollX\n } else {\n left = rect.right + scrollX\n }\n\n setPosition({ top, left })\n }\n\n updatePosition()\n window.addEventListener('resize', updatePosition)\n window.addEventListener('scroll', updatePosition, true)\n\n return () => {\n window.removeEventListener('resize', updatePosition)\n window.removeEventListener('scroll', updatePosition, true)\n }\n }, [isOpen, placement, offset, mounted])\n\n // Close on outside click\n useEffect(() => {\n if (!isOpen) return\n\n const handleClick = (e: MouseEvent) => {\n if (\n triggerRef.current?.contains(e.target as Node) ||\n menuRef.current?.contains(e.target as Node)\n ) {\n return\n }\n setIsOpen(false)\n }\n\n document.addEventListener('mousedown', handleClick)\n return () => document.removeEventListener('mousedown', handleClick)\n }, [isOpen, setIsOpen])\n\n // Keyboard navigation\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (!isOpen) {\n if (e.key === 'ArrowDown' || e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n setIsOpen(true)\n }\n return\n }\n\n const items = menuRef.current?.querySelectorAll<HTMLElement>('[role=\"menuitem\"]:not([aria-disabled=\"true\"])')\n if (!items?.length) return\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n setActiveIndex((prev) => (prev + 1) % items.length)\n break\n case 'ArrowUp':\n e.preventDefault()\n setActiveIndex((prev) => (prev - 1 + items.length) % items.length)\n break\n case 'Home':\n e.preventDefault()\n setActiveIndex(0)\n break\n case 'End':\n e.preventDefault()\n setActiveIndex(items.length - 1)\n break\n case 'Escape':\n e.preventDefault()\n setIsOpen(false)\n triggerRef.current?.focus()\n break\n case 'Enter':\n case ' ':\n e.preventDefault()\n if (activeIndex >= 0) {\n items[activeIndex]?.click()\n }\n break\n }\n },\n [isOpen, activeIndex, setIsOpen]\n )\n\n // Focus active item\n useEffect(() => {\n if (!isOpen || activeIndex < 0) return\n const items = menuRef.current?.querySelectorAll<HTMLElement>('[role=\"menuitem\"]:not([aria-disabled=\"true\"])')\n items?.[activeIndex]?.focus()\n }, [isOpen, activeIndex])\n\n const triggerProps = trigger.props as Record<string, unknown>\n const triggerElement = cloneElement(trigger as ReactElement<Record<string, unknown>>, {\n ref: triggerRef,\n 'aria-haspopup': 'menu',\n 'aria-expanded': isOpen,\n onClick: (e: React.MouseEvent) => {\n (triggerProps.onClick as ((e: React.MouseEvent) => void) | undefined)?.(e)\n setIsOpen(!isOpen)\n },\n onKeyDown: (e: KeyboardEvent) => {\n (triggerProps.onKeyDown as ((e: KeyboardEvent) => void) | undefined)?.(e)\n handleKeyDown(e)\n },\n })\n\n // Only layout-related inline styles (position is dynamic)\n const menuStyle: CSSProperties = {\n position: 'absolute',\n top: position.top,\n left: placement.endsWith('end') ? 'auto' : position.left,\n right: placement.endsWith('end') ? window.innerWidth - position.left : 'auto',\n minWidth: triggerRef.current?.offsetWidth ?? 160,\n ...style,\n }\n\n return (\n <DropdownContext.Provider value={{ isOpen, close: closeOnSelect ? close : () => {}, activeIndex, setActiveIndex }}>\n <div\n ref={ref}\n className={cx('brycks-dropdown', className)}\n data-testid={testId}\n {...props}\n >\n {triggerElement}\n {isOpen && mounted && createPortal(\n <div\n ref={menuRef}\n role=\"menu\"\n className=\"brycks-dropdown__menu\"\n style={menuStyle}\n onKeyDown={handleKeyDown}\n tabIndex={-1}\n >\n {children}\n </div>,\n document.body\n )}\n </div>\n </DropdownContext.Provider>\n )\n})\n\nDropdown.displayName = 'Dropdown'\n\n// DropdownItem\nexport interface DropdownItemProps extends HTMLAttributes<HTMLDivElement> {\n /** Whether the item is disabled */\n disabled?: boolean\n /** Icon before the label */\n icon?: ReactNode\n /** Shortcut text */\n shortcut?: string\n /** Whether the item is destructive */\n destructive?: boolean\n /** Custom class name */\n className?: string\n}\n\nexport const DropdownItem = forwardRef<HTMLDivElement, DropdownItemProps>(function DropdownItem(\n { disabled = false, icon, shortcut, destructive = false, className, style, children, onClick, ...props },\n ref\n) {\n const { close } = useDropdownContext()\n\n const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {\n if (disabled) return\n onClick?.(e)\n close()\n }\n\n return (\n <div\n ref={ref}\n role=\"menuitem\"\n aria-disabled={disabled}\n tabIndex={disabled ? -1 : 0}\n className={cx(\n 'brycks-dropdown-item',\n disabled && 'brycks-dropdown-item--disabled',\n destructive && 'brycks-dropdown-item--destructive',\n className\n )}\n style={style}\n onClick={handleClick}\n {...props}\n >\n {icon && <span className=\"brycks-dropdown-item__icon\">{icon}</span>}\n <span className=\"brycks-dropdown-item__label\">{children}</span>\n {shortcut && <span className=\"brycks-dropdown-item__shortcut\">{shortcut}</span>}\n </div>\n )\n})\n\nDropdownItem.displayName = 'DropdownItem'\n\n// DropdownDivider\nexport interface DropdownDividerProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name */\n className?: string\n}\n\nexport const DropdownDivider = forwardRef<HTMLDivElement, DropdownDividerProps>(function DropdownDivider(\n { className, style, ...props },\n ref\n) {\n return (\n <div\n ref={ref}\n role=\"separator\"\n className={cx('brycks-dropdown-divider', className)}\n style={style}\n {...props}\n />\n )\n})\n\nDropdownDivider.displayName = 'DropdownDivider'\n\n// DropdownLabel\nexport interface DropdownLabelProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name */\n className?: string\n}\n\nexport const DropdownLabel = forwardRef<HTMLDivElement, DropdownLabelProps>(function DropdownLabel(\n { className, style, children, ...props },\n ref\n) {\n return (\n <div\n ref={ref}\n className={cx('brycks-dropdown-label', className)}\n style={style}\n {...props}\n >\n {children}\n </div>\n )\n})\n\nDropdownLabel.displayName = 'DropdownLabel'\n"],"names":["DropdownContext","createContext","useDropdownContext","context","useContext","Dropdown","forwardRef","trigger","controlledIsOpen","defaultOpen","onOpenChange","placement","offset","closeOnSelect","className","style","children","testId","props","ref","internalIsOpen","setInternalIsOpen","useState","position","setPosition","activeIndex","setActiveIndex","mounted","setMounted","triggerRef","useRef","menuRef","isOpen","useEffect","setIsOpen","useCallback","open","close","updatePosition","rect","scrollX","scrollY","top","left","handleClick","e","handleKeyDown","items","prev","triggerProps","triggerElement","cloneElement","menuStyle","jsx","jsxs","cx","createPortal","DropdownItem","disabled","icon","shortcut","destructive","onClick","DropdownDivider","DropdownLabel"],"mappings":"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"}
|