@brycks/core-front 0.3.1 → 0.3.2
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/data/List/List.cjs +1 -1
- package/dist/components/data/List/List.cjs.map +1 -1
- package/dist/components/data/List/List.js +92 -88
- package/dist/components/data/List/List.js.map +1 -1
- package/dist/components/data/Table/Table.cjs +1 -1
- package/dist/components/data/Table/Table.cjs.map +1 -1
- package/dist/components/data/Table/Table.js +129 -125
- package/dist/components/data/Table/Table.js.map +1 -1
- package/dist/components/data/TreeView/TreeView.cjs +2 -0
- package/dist/components/data/TreeView/TreeView.cjs.map +1 -0
- package/dist/components/data/TreeView/TreeView.js +256 -0
- package/dist/components/data/TreeView/TreeView.js.map +1 -0
- package/dist/components/data/VirtualList/VirtualList.cjs +2 -0
- package/dist/components/data/VirtualList/VirtualList.cjs.map +1 -0
- package/dist/components/data/VirtualList/VirtualList.js +186 -0
- package/dist/components/data/VirtualList/VirtualList.js.map +1 -0
- package/dist/components/data.cjs +1 -1
- package/dist/components/data.js +21 -16
- package/dist/components/data.js.map +1 -1
- package/dist/components/feedback/Modal/Modal.cjs +1 -1
- package/dist/components/feedback/Modal/Modal.cjs.map +1 -1
- package/dist/components/feedback/Modal/Modal.js +81 -77
- package/dist/components/feedback/Modal/Modal.js.map +1 -1
- package/dist/components/form/Combobox/Combobox.cjs +7 -0
- package/dist/components/form/Combobox/Combobox.cjs.map +1 -0
- package/dist/components/form/Combobox/Combobox.js +338 -0
- package/dist/components/form/Combobox/Combobox.js.map +1 -0
- package/dist/components/form/DateRangePicker/DateRangePicker.cjs +2 -0
- package/dist/components/form/DateRangePicker/DateRangePicker.cjs.map +1 -0
- package/dist/components/form/DateRangePicker/DateRangePicker.js +372 -0
- package/dist/components/form/DateRangePicker/DateRangePicker.js.map +1 -0
- package/dist/components/form/MultiSelect/MultiSelect.cjs +2 -0
- package/dist/components/form/MultiSelect/MultiSelect.cjs.map +1 -0
- package/dist/components/form/MultiSelect/MultiSelect.js +393 -0
- package/dist/components/form/MultiSelect/MultiSelect.js.map +1 -0
- package/dist/components/form/Rating/Rating.cjs +2 -0
- package/dist/components/form/Rating/Rating.cjs.map +1 -0
- package/dist/components/form/Rating/Rating.js +163 -0
- package/dist/components/form/Rating/Rating.js.map +1 -0
- package/dist/components/form/Slider/Slider.cjs +1 -1
- package/dist/components/form/Slider/Slider.cjs.map +1 -1
- package/dist/components/form/Slider/Slider.js +120 -85
- package/dist/components/form/Slider/Slider.js.map +1 -1
- package/dist/components/form/TagInput/TagInput.cjs +2 -0
- package/dist/components/form/TagInput/TagInput.cjs.map +1 -0
- package/dist/components/form/TagInput/TagInput.js +286 -0
- package/dist/components/form/TagInput/TagInput.js.map +1 -0
- package/dist/components/form/TimePicker/TimePicker.cjs +2 -0
- package/dist/components/form/TimePicker/TimePicker.cjs.map +1 -0
- package/dist/components/form/TimePicker/TimePicker.js +328 -0
- package/dist/components/form/TimePicker/TimePicker.js.map +1 -0
- package/dist/components/form.cjs +1 -1
- package/dist/components/form.js +34 -22
- package/dist/components/form.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 +62 -59
- package/dist/components/layout/Card/Card.js.map +1 -1
- package/dist/components/layout/Collapse/Collapse.cjs +2 -0
- package/dist/components/layout/Collapse/Collapse.cjs.map +1 -0
- package/dist/components/layout/Collapse/Collapse.js +140 -0
- package/dist/components/layout/Collapse/Collapse.js.map +1 -0
- package/dist/components/layout.cjs +1 -1
- package/dist/components/layout.js +27 -24
- package/dist/components/layout.js.map +1 -1
- package/dist/components/navigation/Breadcrumb/Breadcrumb.cjs +1 -1
- package/dist/components/navigation/Breadcrumb/Breadcrumb.cjs.map +1 -1
- package/dist/components/navigation/Breadcrumb/Breadcrumb.js +66 -62
- package/dist/components/navigation/Breadcrumb/Breadcrumb.js.map +1 -1
- package/dist/components/navigation/ContextMenu/ContextMenu.cjs +2 -0
- package/dist/components/navigation/ContextMenu/ContextMenu.cjs.map +1 -0
- package/dist/components/navigation/ContextMenu/ContextMenu.js +227 -0
- package/dist/components/navigation/ContextMenu/ContextMenu.js.map +1 -0
- package/dist/components/navigation/Dropdown/Dropdown.cjs +2 -2
- package/dist/components/navigation/Dropdown/Dropdown.cjs.map +1 -1
- package/dist/components/navigation/Dropdown/Dropdown.js +84 -80
- 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.cjs.map +1 -1
- package/dist/components/navigation/Menu/Menu.js +132 -94
- package/dist/components/navigation/Menu/Menu.js.map +1 -1
- package/dist/components/navigation/Pagination/Pagination.cjs +1 -1
- package/dist/components/navigation/Pagination/Pagination.cjs.map +1 -1
- package/dist/components/navigation/Pagination/Pagination.js +111 -107
- package/dist/components/navigation/Pagination/Pagination.js.map +1 -1
- package/dist/components/navigation/Stepper/Stepper.cjs +2 -0
- package/dist/components/navigation/Stepper/Stepper.cjs.map +1 -0
- package/dist/components/navigation/Stepper/Stepper.js +187 -0
- package/dist/components/navigation/Stepper/Stepper.js.map +1 -0
- package/dist/components/navigation.cjs +1 -1
- package/dist/components/navigation.js +27 -21
- package/dist/components/navigation.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 +38 -35
- package/dist/components/utility/Badge/Badge.js.map +1 -1
- package/dist/data.d.ts +116 -0
- package/dist/form.d.ts +316 -0
- package/dist/hooks/useInteractionState.cjs +2 -0
- package/dist/hooks/useInteractionState.cjs.map +1 -0
- package/dist/hooks/useInteractionState.js +67 -0
- package/dist/hooks/useInteractionState.js.map +1 -0
- package/dist/hooks.cjs +1 -1
- package/dist/hooks.d.ts +87 -0
- package/dist/hooks.js +16 -14
- package/dist/hooks.js.map +1 -1
- package/dist/layout.d.ts +44 -0
- package/dist/navigation.d.ts +88 -0
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("react/jsx-runtime"),r=require("react"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("react/jsx-runtime"),r=require("react"),Q=require("react-dom"),x=require("../../../utils/styles.cjs"),f=require("../../../design-system/primitives/sizing.cjs"),v=require("../../../design-system/tokens/motion.cjs"),N=require("../../../design-system/tokens/spacing.cjs"),$=require("../../../design-system/tokens/typography.cjs"),X=r.createContext(null);function V(){const b=r.useContext(X);if(!b)throw new Error("Dropdown components must be used within a Dropdown");return b}const K=r.forwardRef(function({trigger:t,isOpen:c,defaultOpen:l=!1,onOpenChange:d,placement:i="bottom-start",offset:m=4,closeOnSelect:D=!0,className:h,style:S,children:C,testId:E,...j},z){const[R,I]=r.useState(l),[n,G]=r.useState({top:0,left:0}),[y,g]=r.useState(-1),[L,W]=r.useState(!1),w=r.useRef(null),k=r.useRef(null),o=c??R;r.useEffect(()=>(W(!0),()=>W(!1)),[]);const u=r.useCallback(e=>{c===void 0&&I(e),d?.(e),e||g(-1)},[c,d]),H=r.useCallback(()=>u(!1),[u]);r.useEffect(()=>{if(!o||!w.current||!L)return;const e=()=>{const s=w.current;if(!s)return;const p=s.getBoundingClientRect(),Y=window.scrollX,O=window.scrollY;let q=0,P=0;i.startsWith("bottom")?q=p.bottom+O+m:q=p.top+O-m,i.endsWith("start")?P=p.left+Y:P=p.right+Y,G({top:q,left:P})};return e(),window.addEventListener("resize",e),window.addEventListener("scroll",e,!0),()=>{window.removeEventListener("resize",e),window.removeEventListener("scroll",e,!0)}},[o,i,m,L]),r.useEffect(()=>{if(!o)return;const e=s=>{w.current?.contains(s.target)||k.current?.contains(s.target)||u(!1)};return document.addEventListener("mousedown",e),()=>document.removeEventListener("mousedown",e)},[o,u]);const A=r.useCallback(e=>{if(!o){(e.key==="ArrowDown"||e.key==="Enter"||e.key===" ")&&(e.preventDefault(),u(!0));return}const s=k.current?.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])');if(s?.length)switch(e.key){case"ArrowDown":e.preventDefault(),g(p=>(p+1)%s.length);break;case"ArrowUp":e.preventDefault(),g(p=>(p-1+s.length)%s.length);break;case"Home":e.preventDefault(),g(0);break;case"End":e.preventDefault(),g(s.length-1);break;case"Escape":e.preventDefault(),u(!1),w.current?.focus();break;case"Enter":case" ":e.preventDefault(),y>=0&&s[y]?.click();break}},[o,y,u]);r.useEffect(()=>{if(!o||y<0)return;k.current?.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')?.[y]?.focus()},[o,y]);const T=t.props,U=r.cloneElement(t,{ref:w,"aria-haspopup":"menu","aria-expanded":o,onClick:e=>{T.onClick?.(e),u(!o)},onKeyDown:e=>{T.onKeyDown?.(e),A(e)}}),J={position:"absolute",top:n.top,left:i.endsWith("end")?"auto":n.left,right:i.endsWith("end")?window.innerWidth-n.left:"auto",zIndex:"var(--brycks-z-dropdown)",minWidth:w.current?.offsetWidth??160,backgroundColor:"var(--brycks-background-elevated)",border:"1px solid var(--brycks-border-default)",borderRadius:"var(--brycks-radius-lg)",boxShadow:"var(--brycks-shadow-lg)",padding:N.spacing[1],animation:`brycks-dropdown-in ${v.durations.quick}ms ${v.easings.easeOut}`,outline:"none",...S};return a.jsx(X.Provider,{value:{isOpen:o,close:D?H:()=>{},activeIndex:y,setActiveIndex:g},children:a.jsxs("div",{ref:z,className:x.cx("brycks-dropdown",h),style:{display:"inline-block"},"data-testid":E,...j,children:[U,o&&L&&Q.createPortal(a.jsxs(a.Fragment,{children:[a.jsx("style",{children:`
|
|
2
2
|
@keyframes brycks-dropdown-in {
|
|
3
3
|
from { opacity: 0; transform: translateY(-4px); }
|
|
4
4
|
to { opacity: 1; transform: translateY(0); }
|
|
5
5
|
}
|
|
6
|
-
`}),a.jsx("div",{ref:k,role:"menu",style:
|
|
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;
|
|
7
7
|
//# 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'\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: 4,\n animation: 'brycks-dropdown-in 150ms ease-out',\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: 10,\n padding: '8px 12px',\n fontSize: 14,\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 100ms ease-out',\n outline: 'none',\n ...style,\n }\n\n const iconStyle: CSSProperties = {\n width: 16,\n height: 16,\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: 12,\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: '4px 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: '8px 12px 4px 12px',\n fontSize: 11,\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","jsx","jsxs","cx","createPortal","Fragment","DropdownItem","disabled","icon","shortcut","destructive","onClick","itemStyle","iconStyle","shortcutStyle","DropdownDivider","dividerStyle","DropdownLabel","labelStyle"],"mappings":"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"}
|
|
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":"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"}
|
|
@@ -1,69 +1,73 @@
|
|
|
1
|
-
import { jsx as u, jsxs as
|
|
2
|
-
import { forwardRef as v, useState as k, useRef as
|
|
3
|
-
import { createPortal as
|
|
1
|
+
import { jsx as u, jsxs as A, Fragment as ee } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef as v, useState as k, useRef as j, useEffect as g, useCallback as R, cloneElement as re, createContext as te, useContext as oe } from "react";
|
|
3
|
+
import { createPortal as ne } from "react-dom";
|
|
4
4
|
import { cx as h } from "../../../utils/styles.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
import { componentPaddingY as G, componentPaddingX as T, componentGap as se, iconSizes as B } from "../../../design-system/primitives/sizing.js";
|
|
6
|
+
import { durations as H, easings as U } from "../../../design-system/tokens/motion.js";
|
|
7
|
+
import { spacing as K } from "../../../design-system/tokens/spacing.js";
|
|
8
|
+
import { fontSizes as Y } from "../../../design-system/tokens/typography.js";
|
|
9
|
+
const J = te(null);
|
|
10
|
+
function ae() {
|
|
11
|
+
const f = oe(J);
|
|
12
|
+
if (!f)
|
|
9
13
|
throw new Error("Dropdown components must be used within a Dropdown");
|
|
10
|
-
return
|
|
14
|
+
return f;
|
|
11
15
|
}
|
|
12
|
-
const
|
|
16
|
+
const ie = v(function({
|
|
13
17
|
trigger: r,
|
|
14
18
|
isOpen: a,
|
|
15
|
-
defaultOpen:
|
|
19
|
+
defaultOpen: c = !1,
|
|
16
20
|
onOpenChange: i,
|
|
17
21
|
placement: s = "bottom-start",
|
|
18
22
|
offset: p = 4,
|
|
19
23
|
closeOnSelect: D = !0,
|
|
20
24
|
className: x,
|
|
21
25
|
style: C,
|
|
22
|
-
children:
|
|
23
|
-
testId:
|
|
26
|
+
children: S,
|
|
27
|
+
testId: E,
|
|
24
28
|
...I
|
|
25
29
|
}, L) {
|
|
26
|
-
const [
|
|
27
|
-
g(() => (
|
|
28
|
-
const
|
|
30
|
+
const [$, z] = k(c), [t, Q] = k({ top: 0, left: 0 }), [m, y] = k(-1), [N, O] = k(!1), b = j(null), w = j(null), o = a ?? $;
|
|
31
|
+
g(() => (O(!0), () => O(!1)), []);
|
|
32
|
+
const d = R(
|
|
29
33
|
(e) => {
|
|
30
|
-
a === void 0 &&
|
|
34
|
+
a === void 0 && z(e), i?.(e), e || y(-1);
|
|
31
35
|
},
|
|
32
36
|
[a, i]
|
|
33
|
-
),
|
|
37
|
+
), V = R(() => d(!1), [d]);
|
|
34
38
|
g(() => {
|
|
35
|
-
if (!o || !b.current || !
|
|
39
|
+
if (!o || !b.current || !N) return;
|
|
36
40
|
const e = () => {
|
|
37
41
|
const n = b.current;
|
|
38
42
|
if (!n) return;
|
|
39
|
-
const
|
|
40
|
-
let
|
|
41
|
-
s.startsWith("bottom") ?
|
|
43
|
+
const l = n.getBoundingClientRect(), M = window.scrollX, X = window.scrollY;
|
|
44
|
+
let W = 0, P = 0;
|
|
45
|
+
s.startsWith("bottom") ? W = l.bottom + X + p : W = l.top + X - p, s.endsWith("start") ? P = l.left + M : P = l.right + M, Q({ top: W, left: P });
|
|
42
46
|
};
|
|
43
47
|
return e(), window.addEventListener("resize", e), window.addEventListener("scroll", e, !0), () => {
|
|
44
48
|
window.removeEventListener("resize", e), window.removeEventListener("scroll", e, !0);
|
|
45
49
|
};
|
|
46
|
-
}, [o, s, p,
|
|
50
|
+
}, [o, s, p, N]), g(() => {
|
|
47
51
|
if (!o) return;
|
|
48
52
|
const e = (n) => {
|
|
49
|
-
b.current?.contains(n.target) || w.current?.contains(n.target) ||
|
|
53
|
+
b.current?.contains(n.target) || w.current?.contains(n.target) || d(!1);
|
|
50
54
|
};
|
|
51
55
|
return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
|
|
52
|
-
}, [o,
|
|
53
|
-
const
|
|
56
|
+
}, [o, d]);
|
|
57
|
+
const q = R(
|
|
54
58
|
(e) => {
|
|
55
59
|
if (!o) {
|
|
56
|
-
(e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") && (e.preventDefault(),
|
|
60
|
+
(e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") && (e.preventDefault(), d(!0));
|
|
57
61
|
return;
|
|
58
62
|
}
|
|
59
63
|
const n = w.current?.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])');
|
|
60
64
|
if (n?.length)
|
|
61
65
|
switch (e.key) {
|
|
62
66
|
case "ArrowDown":
|
|
63
|
-
e.preventDefault(), y((
|
|
67
|
+
e.preventDefault(), y((l) => (l + 1) % n.length);
|
|
64
68
|
break;
|
|
65
69
|
case "ArrowUp":
|
|
66
|
-
e.preventDefault(), y((
|
|
70
|
+
e.preventDefault(), y((l) => (l - 1 + n.length) % n.length);
|
|
67
71
|
break;
|
|
68
72
|
case "Home":
|
|
69
73
|
e.preventDefault(), y(0);
|
|
@@ -72,31 +76,31 @@ const $ = v(function({
|
|
|
72
76
|
e.preventDefault(), y(n.length - 1);
|
|
73
77
|
break;
|
|
74
78
|
case "Escape":
|
|
75
|
-
e.preventDefault(),
|
|
79
|
+
e.preventDefault(), d(!1), b.current?.focus();
|
|
76
80
|
break;
|
|
77
81
|
case "Enter":
|
|
78
82
|
case " ":
|
|
79
|
-
e.preventDefault(),
|
|
83
|
+
e.preventDefault(), m >= 0 && n[m]?.click();
|
|
80
84
|
break;
|
|
81
85
|
}
|
|
82
86
|
},
|
|
83
|
-
[o,
|
|
87
|
+
[o, m, d]
|
|
84
88
|
);
|
|
85
89
|
g(() => {
|
|
86
|
-
if (!o ||
|
|
87
|
-
w.current?.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')?.[
|
|
88
|
-
}, [o,
|
|
89
|
-
const F = r.props,
|
|
90
|
+
if (!o || m < 0) return;
|
|
91
|
+
w.current?.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')?.[m]?.focus();
|
|
92
|
+
}, [o, m]);
|
|
93
|
+
const F = r.props, Z = re(r, {
|
|
90
94
|
ref: b,
|
|
91
95
|
"aria-haspopup": "menu",
|
|
92
96
|
"aria-expanded": o,
|
|
93
97
|
onClick: (e) => {
|
|
94
|
-
F.onClick?.(e),
|
|
98
|
+
F.onClick?.(e), d(!o);
|
|
95
99
|
},
|
|
96
100
|
onKeyDown: (e) => {
|
|
97
|
-
F.onKeyDown?.(e),
|
|
101
|
+
F.onKeyDown?.(e), q(e);
|
|
98
102
|
}
|
|
99
|
-
}),
|
|
103
|
+
}), _ = {
|
|
100
104
|
position: "absolute",
|
|
101
105
|
top: t.top,
|
|
102
106
|
left: s.endsWith("end") ? "auto" : t.left,
|
|
@@ -107,24 +111,24 @@ const $ = v(function({
|
|
|
107
111
|
border: "1px solid var(--brycks-border-default)",
|
|
108
112
|
borderRadius: "var(--brycks-radius-lg)",
|
|
109
113
|
boxShadow: "var(--brycks-shadow-lg)",
|
|
110
|
-
padding:
|
|
111
|
-
animation:
|
|
114
|
+
padding: K[1],
|
|
115
|
+
animation: `brycks-dropdown-in ${H.quick}ms ${U.easeOut}`,
|
|
112
116
|
outline: "none",
|
|
113
117
|
...C
|
|
114
118
|
};
|
|
115
|
-
return /* @__PURE__ */ u(
|
|
116
|
-
}, activeIndex:
|
|
119
|
+
return /* @__PURE__ */ u(J.Provider, { value: { isOpen: o, close: D ? V : () => {
|
|
120
|
+
}, activeIndex: m, setActiveIndex: y }, children: /* @__PURE__ */ A(
|
|
117
121
|
"div",
|
|
118
122
|
{
|
|
119
123
|
ref: L,
|
|
120
124
|
className: h("brycks-dropdown", x),
|
|
121
125
|
style: { display: "inline-block" },
|
|
122
|
-
"data-testid":
|
|
126
|
+
"data-testid": E,
|
|
123
127
|
...I,
|
|
124
128
|
children: [
|
|
125
|
-
|
|
126
|
-
o &&
|
|
127
|
-
/* @__PURE__ */
|
|
129
|
+
Z,
|
|
130
|
+
o && N && ne(
|
|
131
|
+
/* @__PURE__ */ A(ee, { children: [
|
|
128
132
|
/* @__PURE__ */ u("style", { children: `
|
|
129
133
|
@keyframes brycks-dropdown-in {
|
|
130
134
|
from { opacity: 0; transform: translateY(-4px); }
|
|
@@ -136,10 +140,10 @@ const $ = v(function({
|
|
|
136
140
|
{
|
|
137
141
|
ref: w,
|
|
138
142
|
role: "menu",
|
|
139
|
-
style:
|
|
140
|
-
onKeyDown:
|
|
143
|
+
style: _,
|
|
144
|
+
onKeyDown: q,
|
|
141
145
|
tabIndex: -1,
|
|
142
|
-
children:
|
|
146
|
+
children: S
|
|
143
147
|
}
|
|
144
148
|
)
|
|
145
149
|
] }),
|
|
@@ -149,38 +153,38 @@ const $ = v(function({
|
|
|
149
153
|
}
|
|
150
154
|
) });
|
|
151
155
|
});
|
|
152
|
-
|
|
153
|
-
const
|
|
154
|
-
const { close:
|
|
155
|
-
r || (x?.(t),
|
|
156
|
+
ie.displayName = "Dropdown";
|
|
157
|
+
const ce = v(function({ disabled: r = !1, icon: a, shortcut: c, destructive: i = !1, className: s, style: p, children: D, onClick: x, ...C }, S) {
|
|
158
|
+
const { close: E } = ae(), I = (t) => {
|
|
159
|
+
r || (x?.(t), E());
|
|
156
160
|
}, L = {
|
|
157
161
|
display: "flex",
|
|
158
162
|
alignItems: "center",
|
|
159
|
-
gap:
|
|
160
|
-
padding:
|
|
161
|
-
fontSize:
|
|
163
|
+
gap: se.lg,
|
|
164
|
+
padding: `${G.md}px ${T.sm}px`,
|
|
165
|
+
fontSize: Y.base,
|
|
162
166
|
color: r ? "var(--brycks-foreground-disabled)" : i ? "var(--brycks-error-default)" : "var(--brycks-foreground-default)",
|
|
163
167
|
backgroundColor: "transparent",
|
|
164
168
|
borderRadius: "var(--brycks-radius-md)",
|
|
165
169
|
cursor: r ? "not-allowed" : "pointer",
|
|
166
|
-
transition:
|
|
170
|
+
transition: `background-color ${H.fast}ms ${U.easeOut}`,
|
|
167
171
|
outline: "none",
|
|
168
172
|
...p
|
|
169
|
-
},
|
|
170
|
-
width:
|
|
171
|
-
height:
|
|
173
|
+
}, $ = {
|
|
174
|
+
width: B.sm,
|
|
175
|
+
height: B.sm,
|
|
172
176
|
color: r ? "var(--brycks-foreground-disabled)" : i ? "var(--brycks-error-default)" : "var(--brycks-foreground-muted)",
|
|
173
177
|
flexShrink: 0
|
|
174
|
-
},
|
|
178
|
+
}, z = {
|
|
175
179
|
marginLeft: "auto",
|
|
176
|
-
fontSize:
|
|
180
|
+
fontSize: Y.sm,
|
|
177
181
|
color: "var(--brycks-foreground-muted)",
|
|
178
182
|
fontFamily: "var(--brycks-font-mono)"
|
|
179
183
|
};
|
|
180
|
-
return /* @__PURE__ */
|
|
184
|
+
return /* @__PURE__ */ A(
|
|
181
185
|
"div",
|
|
182
186
|
{
|
|
183
|
-
ref:
|
|
187
|
+
ref: S,
|
|
184
188
|
role: "menuitem",
|
|
185
189
|
"aria-disabled": r,
|
|
186
190
|
tabIndex: r ? -1 : 0,
|
|
@@ -201,19 +205,19 @@ const ee = v(function({ disabled: r = !1, icon: a, shortcut: l, destructive: i =
|
|
|
201
205
|
},
|
|
202
206
|
...C,
|
|
203
207
|
children: [
|
|
204
|
-
a && /* @__PURE__ */ u("span", { style:
|
|
208
|
+
a && /* @__PURE__ */ u("span", { style: $, children: a }),
|
|
205
209
|
/* @__PURE__ */ u("span", { style: { flex: 1 }, children: D }),
|
|
206
|
-
|
|
210
|
+
c && /* @__PURE__ */ u("span", { style: z, children: c })
|
|
207
211
|
]
|
|
208
212
|
}
|
|
209
213
|
);
|
|
210
214
|
});
|
|
211
|
-
|
|
212
|
-
const
|
|
215
|
+
ce.displayName = "DropdownItem";
|
|
216
|
+
const de = v(function({ className: r, style: a, ...c }, i) {
|
|
213
217
|
const s = {
|
|
214
218
|
height: 1,
|
|
215
219
|
backgroundColor: "var(--brycks-border-muted)",
|
|
216
|
-
margin:
|
|
220
|
+
margin: `${K[1]}px 0`,
|
|
217
221
|
...a
|
|
218
222
|
};
|
|
219
223
|
return /* @__PURE__ */ u(
|
|
@@ -223,15 +227,15 @@ const re = v(function({ className: r, style: a, ...l }, i) {
|
|
|
223
227
|
role: "separator",
|
|
224
228
|
className: h("brycks-dropdown-divider", r),
|
|
225
229
|
style: s,
|
|
226
|
-
...
|
|
230
|
+
...c
|
|
227
231
|
}
|
|
228
232
|
);
|
|
229
233
|
});
|
|
230
|
-
|
|
231
|
-
const
|
|
234
|
+
de.displayName = "DropdownDivider";
|
|
235
|
+
const le = v(function({ className: r, style: a, children: c, ...i }, s) {
|
|
232
236
|
const p = {
|
|
233
|
-
padding:
|
|
234
|
-
fontSize:
|
|
237
|
+
padding: `${G.md}px ${T.sm}px ${K[1]}px ${T.sm}px`,
|
|
238
|
+
fontSize: Y.xs,
|
|
235
239
|
fontWeight: 600,
|
|
236
240
|
color: "var(--brycks-foreground-muted)",
|
|
237
241
|
textTransform: "uppercase",
|
|
@@ -245,15 +249,15 @@ const te = v(function({ className: r, style: a, children: l, ...i }, s) {
|
|
|
245
249
|
className: h("brycks-dropdown-label", r),
|
|
246
250
|
style: p,
|
|
247
251
|
...i,
|
|
248
|
-
children:
|
|
252
|
+
children: c
|
|
249
253
|
}
|
|
250
254
|
);
|
|
251
255
|
});
|
|
252
|
-
|
|
256
|
+
le.displayName = "DropdownLabel";
|
|
253
257
|
export {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
+
ie as Dropdown,
|
|
259
|
+
de as DropdownDivider,
|
|
260
|
+
ce as DropdownItem,
|
|
261
|
+
le as DropdownLabel
|
|
258
262
|
};
|
|
259
263
|
//# 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'\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: 4,\n animation: 'brycks-dropdown-in 150ms ease-out',\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: 10,\n padding: '8px 12px',\n fontSize: 14,\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 100ms ease-out',\n outline: 'none',\n ...style,\n }\n\n const iconStyle: CSSProperties = {\n width: 16,\n height: 16,\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: 12,\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: '4px 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: '8px 12px 4px 12px',\n fontSize: 11,\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","jsx","jsxs","cx","createPortal","Fragment","DropdownItem","disabled","icon","shortcut","destructive","onClick","itemStyle","iconStyle","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\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":";;;;;;;;AAoCA,MAAMA,IAAkBC,GAA2C,IAAI;AAEvE,SAASC,KAAqB;AAC5B,QAAMC,IAAUC,GAAWJ,CAAe;AAC1C,MAAI,CAACG;AACH,UAAM,IAAI,MAAM,oDAAoD;AAEtE,SAAOA;AACT;AAuBO,MAAME,KAAWC,EAA0C,SAChE;AAAA,EACE,SAAAC;AAAA,EACA,QAAQC;AAAA,EACR,aAAAC,IAAc;AAAA,EACd,cAAAC;AAAA,EACA,WAAAC,IAAY;AAAA,EACZ,QAAAC,IAAS;AAAA,EACT,eAAAC,IAAgB;AAAA,EAChB,WAAAC;AAAA,EACA,OAAAC;AAAA,EACA,UAAAC;AAAA,EACA,QAAAC;AAAA,EACA,GAAGC;AACL,GACAC,GACA;AACA,QAAM,CAACC,GAAgBC,CAAiB,IAAIC,EAASb,CAAW,GAC1D,CAACc,GAAUC,CAAW,IAAIF,EAAS,EAAE,KAAK,GAAG,MAAM,GAAG,GACtD,CAACG,GAAaC,CAAc,IAAIJ,EAAS,EAAE,GAC3C,CAACK,GAASC,CAAU,IAAIN,EAAS,EAAK,GACtCO,IAAaC,EAAoB,IAAI,GACrCC,IAAUD,EAAuB,IAAI,GAErCE,IAASxB,KAAoBY;AAEnC,EAAAa,EAAU,OACRL,EAAW,EAAI,GACR,MAAMA,EAAW,EAAK,IAC5B,CAAA,CAAE;AAEL,QAAMM,IAAYC;AAAA,IAChB,CAACC,MAAkB;AACjB,MAAI5B,MAAqB,UACvBa,EAAkBe,CAAI,GAExB1B,IAAe0B,CAAI,GACdA,KACHV,EAAe,EAAE;AAAA,IAErB;AAAA,IACA,CAAClB,GAAkBE,CAAY;AAAA,EAAA,GAG3B2B,IAAQF,EAAY,MAAMD,EAAU,EAAK,GAAG,CAACA,CAAS,CAAC;AAG7D,EAAAD,EAAU,MAAM;AACd,QAAI,CAACD,KAAU,CAACH,EAAW,WAAW,CAACF,EAAS;AAEhD,UAAMW,IAAiB,MAAM;AAC3B,YAAM/B,IAAUsB,EAAW;AAC3B,UAAI,CAACtB,EAAS;AAEd,YAAMgC,IAAOhC,EAAQ,sBAAA,GACfiC,IAAU,OAAO,SACjBC,IAAU,OAAO;AAEvB,UAAIC,IAAM,GACNC,IAAO;AAEX,MAAIhC,EAAU,WAAW,QAAQ,IAC/B+B,IAAMH,EAAK,SAASE,IAAU7B,IAE9B8B,IAAMH,EAAK,MAAME,IAAU7B,GAGzBD,EAAU,SAAS,OAAO,IAC5BgC,IAAOJ,EAAK,OAAOC,IAEnBG,IAAOJ,EAAK,QAAQC,GAGtBhB,EAAY,EAAE,KAAAkB,GAAK,MAAAC,GAAM;AAAA,IAC3B;AAEA,WAAAL,EAAA,GACA,OAAO,iBAAiB,UAAUA,CAAc,GAChD,OAAO,iBAAiB,UAAUA,GAAgB,EAAI,GAE/C,MAAM;AACX,aAAO,oBAAoB,UAAUA,CAAc,GACnD,OAAO,oBAAoB,UAAUA,GAAgB,EAAI;AAAA,IAC3D;AAAA,EACF,GAAG,CAACN,GAAQrB,GAAWC,GAAQe,CAAO,CAAC,GAGvCM,EAAU,MAAM;AACd,QAAI,CAACD,EAAQ;AAEb,UAAMY,IAAc,CAACC,MAAkB;AACrC,MACEhB,EAAW,SAAS,SAASgB,EAAE,MAAc,KAC7Cd,EAAQ,SAAS,SAASc,EAAE,MAAc,KAI5CX,EAAU,EAAK;AAAA,IACjB;AAEA,oBAAS,iBAAiB,aAAaU,CAAW,GAC3C,MAAM,SAAS,oBAAoB,aAAaA,CAAW;AAAA,EACpE,GAAG,CAACZ,GAAQE,CAAS,CAAC;AAGtB,QAAMY,IAAgBX;AAAA,IACpB,CAAC,MAAqB;AACpB,UAAI,CAACH,GAAQ;AACX,SAAI,EAAE,QAAQ,eAAe,EAAE,QAAQ,WAAW,EAAE,QAAQ,SAC1D,EAAE,eAAA,GACFE,EAAU,EAAI;AAEhB;AAAA,MACF;AAEA,YAAMa,IAAQhB,EAAQ,SAAS,iBAA8B,+CAA+C;AAC5G,UAAKgB,GAAO;AAEZ,gBAAQ,EAAE,KAAA;AAAA,UACR,KAAK;AACH,cAAE,eAAA,GACFrB,EAAe,CAACsB,OAAUA,IAAO,KAAKD,EAAM,MAAM;AAClD;AAAA,UACF,KAAK;AACH,cAAE,eAAA,GACFrB,EAAe,CAACsB,OAAUA,IAAO,IAAID,EAAM,UAAUA,EAAM,MAAM;AACjE;AAAA,UACF,KAAK;AACH,cAAE,eAAA,GACFrB,EAAe,CAAC;AAChB;AAAA,UACF,KAAK;AACH,cAAE,eAAA,GACFA,EAAeqB,EAAM,SAAS,CAAC;AAC/B;AAAA,UACF,KAAK;AACH,cAAE,eAAA,GACFb,EAAU,EAAK,GACfL,EAAW,SAAS,MAAA;AACpB;AAAA,UACF,KAAK;AAAA,UACL,KAAK;AACH,cAAE,eAAA,GACEJ,KAAe,KACjBsB,EAAMtB,CAAW,GAAG,MAAA;AAEtB;AAAA,QAAA;AAAA,IAEN;AAAA,IACA,CAACO,GAAQP,GAAaS,CAAS;AAAA,EAAA;AAIjC,EAAAD,EAAU,MAAM;AACd,QAAI,CAACD,KAAUP,IAAc,EAAG;AAEhC,IADcM,EAAQ,SAAS,iBAA8B,+CAA+C,IACpGN,CAAW,GAAG,MAAA;AAAA,EACxB,GAAG,CAACO,GAAQP,CAAW,CAAC;AAExB,QAAMwB,IAAe1C,EAAQ,OACvB2C,IAAiBC,GAAa5C,GAAkD;AAAA,IACpF,KAAKsB;AAAA,IACL,iBAAiB;AAAA,IACjB,iBAAiBG;AAAA,IACjB,SAAS,CAAC,MAAwB;AAC/B,MAAAiB,EAAa,UAA0D,CAAC,GACzEf,EAAU,CAACF,CAAM;AAAA,IACnB;AAAA,IACA,WAAW,CAAC,MAAqB;AAC9B,MAAAiB,EAAa,YAAyD,CAAC,GACxEH,EAAc,CAAC;AAAA,IACjB;AAAA,EAAA,CACD,GAEKM,IAA2B;AAAA,IAC/B,UAAU;AAAA,IACV,KAAK7B,EAAS;AAAA,IACd,MAAMZ,EAAU,SAAS,KAAK,IAAI,SAASY,EAAS;AAAA,IACpD,OAAOZ,EAAU,SAAS,KAAK,IAAI,OAAO,aAAaY,EAAS,OAAO;AAAA,IACvE,QAAQ;AAAA,IACR,UAAUM,EAAW,SAAS,eAAe;AAAA,IAC7C,iBAAiB;AAAA,IACjB,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,WAAW;AAAA,IACX,SAASwB,EAAQ,CAAC;AAAA,IAClB,WAAW,sBAAsBC,EAAU,KAAK,MAAMC,EAAQ,OAAO;AAAA,IACrE,SAAS;AAAA,IACT,GAAGxC;AAAA,EAAA;AAGL,SACE,gBAAAyC,EAACxD,EAAgB,UAAhB,EAAyB,OAAO,EAAE,QAAAgC,GAAQ,OAAOnB,IAAgBwB,IAAQ,MAAM;AAAA,EAAC,GAAG,aAAAZ,GAAa,gBAAAC,EAAA,GAC/F,UAAA,gBAAA+B;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAAtC;AAAA,MACA,WAAWuC,EAAG,mBAAmB5C,CAAS;AAAA,MAC1C,OAAO,EAAE,SAAS,eAAA;AAAA,MAClB,eAAaG;AAAA,MACZ,GAAGC;AAAA,MAEH,UAAA;AAAA,QAAAgC;AAAA,QACAlB,KAAUL,KAAWgC;AAAA,UACpB,gBAAAF,EAAAG,IAAA,EACE,UAAA;AAAA,YAAA,gBAAAJ,EAAC,SAAA,EACE,UAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAMH;AAAA,YACA,gBAAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,KAAKzB;AAAA,gBACL,MAAK;AAAA,gBACL,OAAOqB;AAAA,gBACP,WAAWN;AAAA,gBACX,UAAU;AAAA,gBAET,UAAA9B;AAAA,cAAA;AAAA,YAAA;AAAA,UACH,GACF;AAAA,UACA,SAAS;AAAA,QAAA;AAAA,MACX;AAAA,IAAA;AAAA,EAAA,GAEJ;AAEJ,CAAC;AAEDX,GAAS,cAAc;AAgBhB,MAAMwD,KAAevD,EAA8C,SACxE,EAAE,UAAAwD,IAAW,IAAO,MAAAC,GAAM,UAAAC,GAAU,aAAAC,IAAc,IAAO,WAAAnD,GAAW,OAAAC,GAAO,UAAAC,GAAU,SAAAkD,GAAS,GAAGhD,EAAA,GACjGC,GACA;AACA,QAAM,EAAE,OAAAkB,EAAA,IAAUnC,GAAA,GAEZ0C,IAAc,CAACC,MAAwC;AAC3D,IAAIiB,MACJI,IAAUrB,CAAC,GACXR,EAAA;AAAA,EACF,GAEM8B,IAA2B;AAAA,IAC/B,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,KAAKC,GAAa;AAAA,IAClB,SAAS,GAAGC,EAAkB,EAAE,MAAMC,EAAkB,EAAE;AAAA,IAC1D,UAAUC,EAAU;AAAA,IACpB,OAAOT,IACH,sCACAG,IACA,gCACA;AAAA,IACJ,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,QAAQH,IAAW,gBAAgB;AAAA,IACnC,YAAY,oBAAoBR,EAAU,IAAI,MAAMC,EAAQ,OAAO;AAAA,IACnE,SAAS;AAAA,IACT,GAAGxC;AAAA,EAAA,GAGCyD,IAA2B;AAAA,IAC/B,OAAOC,EAAU;AAAA,IACjB,QAAQA,EAAU;AAAA,IAClB,OAAOX,IACH,sCACAG,IACA,gCACA;AAAA,IACJ,YAAY;AAAA,EAAA,GAGRS,IAA+B;AAAA,IACnC,YAAY;AAAA,IACZ,UAAUH,EAAU;AAAA,IACpB,OAAO;AAAA,IACP,YAAY;AAAA,EAAA;AAGd,SACE,gBAAAd;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAAtC;AAAA,MACA,MAAK;AAAA,MACL,iBAAe2C;AAAA,MACf,UAAUA,IAAW,KAAK;AAAA,MAC1B,WAAWJ,EAAG,wBAAwBI,KAAY,kCAAkChD,CAAS;AAAA,MAC7F,OAAOqD;AAAA,MACP,SAASvB;AAAA,MACT,cAAc,CAACC,MAAM;AACnB,QAAKiB,MACHjB,EAAE,cAAc,MAAM,kBAAkB;AAAA,MAE5C;AAAA,MACA,cAAc,CAACA,MAAM;AACnB,QAAAA,EAAE,cAAc,MAAM,kBAAkB;AAAA,MAC1C;AAAA,MACA,SAAS,CAACA,MAAM;AACd,QAAAA,EAAE,cAAc,MAAM,kBAAkB;AAAA,MAC1C;AAAA,MACA,QAAQ,CAACA,MAAM;AACb,QAAAA,EAAE,cAAc,MAAM,kBAAkB;AAAA,MAC1C;AAAA,MACC,GAAG3B;AAAA,MAEH,UAAA;AAAA,QAAA6C,KAAQ,gBAAAP,EAAC,QAAA,EAAK,OAAOgB,GAAY,UAAAT,GAAK;AAAA,0BACtC,QAAA,EAAK,OAAO,EAAE,MAAM,EAAA,GAAM,UAAA/C,GAAS;AAAA,QACnCgD,KAAY,gBAAAR,EAAC,QAAA,EAAK,OAAOkB,GAAgB,UAAAV,EAAA,CAAS;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGzD,CAAC;AAEDH,GAAa,cAAc;AAQpB,MAAMc,KAAkBrE,EAAiD,SAC9E,EAAE,WAAAQ,GAAW,OAAAC,GAAO,GAAGG,EAAA,GACvBC,GACA;AACA,QAAMyD,IAA8B;AAAA,IAClC,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,QAAQ,GAAGvB,EAAQ,CAAC,CAAC;AAAA,IACrB,GAAGtC;AAAA,EAAA;AAGL,SACE,gBAAAyC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAArC;AAAA,MACA,MAAK;AAAA,MACL,WAAWuC,EAAG,2BAA2B5C,CAAS;AAAA,MAClD,OAAO8D;AAAA,MACN,GAAG1D;AAAA,IAAA;AAAA,EAAA;AAGV,CAAC;AAEDyD,GAAgB,cAAc;AAQvB,MAAME,KAAgBvE,EAA+C,SAC1E,EAAE,WAAAQ,GAAW,OAAAC,GAAO,UAAAC,GAAU,GAAGE,EAAA,GACjCC,GACA;AACA,QAAM2D,IAA4B;AAAA,IAChC,SAAS,GAAGT,EAAkB,EAAE,MAAMC,EAAkB,EAAE,MAAMjB,EAAQ,CAAC,CAAC,MAAMiB,EAAkB,EAAE;AAAA,IACpG,UAAUC,EAAU;AAAA,IACpB,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,eAAe;AAAA,IACf,eAAe;AAAA,IACf,GAAGxD;AAAA,EAAA;AAGL,SACE,gBAAAyC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAArC;AAAA,MACA,WAAWuC,EAAG,yBAAyB5C,CAAS;AAAA,MAChD,OAAOgE;AAAA,MACN,GAAG5D;AAAA,MAEH,UAAAF;AAAA,IAAA;AAAA,EAAA;AAGP,CAAC;AAED6D,GAAc,cAAc;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("react/jsx-runtime"),r=require("react"),j=require("../../../utils/styles.cjs"),m=require("../../../design-system/tokens/spacing.cjs"),N=require("../../../design-system/tokens/motion.cjs"),i=require("../../../design-system/primitives/sizing.cjs"),C=require("../../../design-system/tokens/typography.cjs"),A=r.createContext(null);function G(){const f=r.useContext(A);if(!f)throw new Error("Menu components must be used within a Menu");return f}const H=r.forwardRef(function({activeItem:t,onChange:u,size:c="md",collapsed:s=!1,className:p,style:b,children:S,testId:g,...v},y){const[D,R]=r.useState(null),[x,o]=r.useState(-1),k=r.useRef([]),I=r.useRef(null),q=t!==void 0?t:D,l=e=>{t===void 0&&R(e),u?.(e)},d=r.useCallback(e=>{const n=k.current.indexOf(e);return n===-1?(k.current.push(e),k.current.length-1):n},[]),M=r.useCallback(e=>{const n=I.current?.querySelectorAll('[role="menuitem"]:not(:disabled)');if(!n?.length)return;const z=x>=0?x:0;switch(e.key){case"ArrowDown":e.preventDefault();const w=(z+1)%n.length;o(w),n[w]?.focus();break;case"ArrowUp":e.preventDefault();const h=(z-1+n.length)%n.length;o(h),n[h]?.focus();break;case"Home":e.preventDefault(),o(0),n[0]?.focus();break;case"End":e.preventDefault(),o(n.length-1),n[n.length-1]?.focus();break}},[x]),$={display:"flex",flexDirection:"column",gap:m.spacing[.5],padding:m.spacing[2],...b};return a.jsx(A.Provider,{value:{size:c,activeItem:q,setActiveItem:l,collapsed:s,focusedIndex:x,setFocusedIndex:o,registerItem:d},children:a.jsx("nav",{ref:e=>{I.current=e,typeof y=="function"?y(e):y&&(y.current=e)},role:"menu",className:j.cx("brycks-menu",`brycks-menu--${c}`,s&&"brycks-menu--collapsed",p),style:$,onKeyDown:M,"data-testid":g,...v,children:S})})});H.displayName="Menu";const E={sm:{height:i.componentHeights.sm,fontSize:C.fontSizes.base-1,iconSize:i.iconSizes.sm,padding:i.componentGap.lg},md:{height:i.componentHeights.md,fontSize:C.fontSizes.base,iconSize:i.iconSizes.md-2,padding:i.componentPaddingX.sm},lg:{height:i.componentHeights.lg,fontSize:C.fontSizes.md,iconSize:i.iconSizes.md,padding:m.spacing[3.5]}},F=r.forwardRef(function({value:t,icon:u,badge:c,disabled:s=!1,onClick:p,className:b,style:S,children:g,...v},y){const{size:D,activeItem:R,setActiveItem:x,collapsed:o,focusedIndex:k,setFocusedIndex:I,registerItem:q}=G(),l=R===t,d=E[D],M=q(t),$=()=>{s||(x(t),p?.(t))},e=()=>{I(M)},n={display:"flex",alignItems:"center",gap:i.componentGap.lg,width:"100%",minHeight:d.height,padding:o?d.padding:`0 ${d.padding}px`,fontSize:d.fontSize,fontWeight:l?600:500,color:s?"var(--brycks-foreground-disabled)":l?"var(--brycks-primary-default)":"var(--brycks-foreground-default)",backgroundColor:l?"var(--brycks-primary-50)":"transparent",border:"none",borderRadius:"var(--brycks-radius-md)",cursor:s?"not-allowed":"pointer",transition:`all ${N.durations.quick}ms ${N.easings.easeOut}`,textAlign:"left",outline:"none",justifyContent:o?"center":"flex-start",...S},z={width:d.iconSize,height:d.iconSize,flexShrink:0,display:"flex",alignItems:"center",justifyContent:"center"},w={marginLeft:"auto"};return a.jsxs("button",{ref:y,type:"button",role:"menuitem",disabled:s,tabIndex:k===M?0:-1,className:j.cx("brycks-menu-item",l&&"brycks-menu-item--active",b),style:n,onClick:$,onFocus:e,onMouseEnter:h=>{!s&&!l&&(h.currentTarget.style.backgroundColor="var(--brycks-background-muted)")},onMouseLeave:h=>{l||(h.currentTarget.style.backgroundColor="transparent")},title:o?String(g):void 0,...v,children:[u&&a.jsx("span",{style:z,children:u}),!o&&a.jsx("span",{style:{flex:1},children:g}),!o&&c&&a.jsx("span",{style:w,children:c})]})});F.displayName="MenuItem";const P=r.forwardRef(function({label:t,className:u,style:c,children:s,...p},b){const{collapsed:S}=G(),g={display:"flex",flexDirection:"column",gap:m.spacing[.5],...c},v={padding:`${m.spacing[3]}px ${m.spacing[3]}px ${i.componentPaddingY.sm}px ${m.spacing[3]}px`,fontSize:C.fontSizes.xs,fontWeight:600,color:"var(--brycks-foreground-muted)",textTransform:"uppercase",letterSpacing:"0.05em"};return a.jsxs("div",{ref:b,className:j.cx("brycks-menu-group",u),style:g,...p,children:[t&&!S&&a.jsx("div",{style:v,children:t}),s]})});P.displayName="MenuGroup";const T=r.forwardRef(function({className:t,style:u,...c},s){const p={height:1,backgroundColor:"var(--brycks-border-muted)",margin:`${m.spacing[2]}px 0`,...u};return a.jsx("div",{ref:s,role:"separator",className:j.cx("brycks-menu-divider",t),style:p,...c})});T.displayName="MenuDivider";exports.Menu=H;exports.MenuDivider=T;exports.MenuGroup=P;exports.MenuItem=F;
|
|
2
2
|
//# sourceMappingURL=Menu.cjs.map
|