@mantine/core
Version:
React components library focused on usability, accessibility and developer experience
1 lines • 6.38 kB
Source Map (JSON)
{"version":3,"file":"create-scoped-keydown-handler.cjs","names":["findElementAncestor"],"sources":["../../../../src/core/utils/create-scoped-keydown-handler/create-scoped-keydown-handler.ts"],"sourcesContent":["import { findElementAncestor } from '../find-element-ancestor/find-element-ancestor';\n\nfunction getPreviousIndex(current: number, elements: HTMLButtonElement[], loop: boolean) {\n for (let i = current - 1; i >= 0; i -= 1) {\n if (!elements[i].disabled) {\n return i;\n }\n }\n\n if (loop) {\n for (let i = elements.length - 1; i > -1; i -= 1) {\n if (!elements[i].disabled) {\n return i;\n }\n }\n }\n\n return current;\n}\n\nfunction getNextIndex(current: number, elements: HTMLButtonElement[], loop: boolean) {\n for (let i = current + 1; i < elements.length; i += 1) {\n if (!elements[i].disabled) {\n return i;\n }\n }\n\n if (loop) {\n for (let i = 0; i < elements.length; i += 1) {\n if (!elements[i].disabled) {\n return i;\n }\n }\n }\n\n return current;\n}\n\n/** Validates that target element is on the same level as sibling, used to filter out children that have the same sibling selector */\nfunction onSameLevel(\n target: HTMLButtonElement,\n sibling: HTMLButtonElement,\n parentSelector: string\n) {\n return (\n findElementAncestor(target, parentSelector) === findElementAncestor(sibling, parentSelector)\n );\n}\n\ninterface GetElementsSiblingsInput {\n /** Selector used to find parent node, for example '[role=\"tablist\"]', '.mantine-Text-root' */\n parentSelector: string;\n\n /** Selector used to find element siblings, for example '[data-tab]' */\n siblingSelector: string;\n\n /** Determines whether next/previous indices should loop */\n loop?: boolean;\n\n /** Determines which arrow keys will be used */\n orientation: 'vertical' | 'horizontal';\n\n /** Text direction */\n dir?: 'rtl' | 'ltr';\n\n /** Determines whether element should be clicked when focused with keyboard event */\n activateOnFocus?: boolean;\n\n /** External keydown event */\n onKeyDown?: (event: React.KeyboardEvent<HTMLButtonElement>) => void;\n}\n\nexport function createScopedKeydownHandler({\n parentSelector,\n siblingSelector,\n onKeyDown,\n loop = true,\n activateOnFocus = false,\n dir = 'rtl',\n orientation,\n}: GetElementsSiblingsInput) {\n return (event: React.KeyboardEvent<HTMLButtonElement>) => {\n onKeyDown?.(event);\n\n const elements = Array.from(\n findElementAncestor(event.currentTarget, parentSelector)?.querySelectorAll<HTMLButtonElement>(\n siblingSelector\n ) || []\n ).filter((node) => onSameLevel(event.currentTarget, node, parentSelector));\n\n const current = elements.findIndex((el) => event.currentTarget === el);\n const _nextIndex = getNextIndex(current, elements, loop);\n const _previousIndex = getPreviousIndex(current, elements, loop);\n const nextIndex = dir === 'rtl' ? _previousIndex : _nextIndex;\n const previousIndex = dir === 'rtl' ? _nextIndex : _previousIndex;\n\n switch (event.key) {\n case 'ArrowRight': {\n if (orientation === 'horizontal') {\n event.stopPropagation();\n event.preventDefault();\n elements[nextIndex].focus();\n activateOnFocus && elements[nextIndex].click();\n }\n\n break;\n }\n\n case 'ArrowLeft': {\n if (orientation === 'horizontal') {\n event.stopPropagation();\n event.preventDefault();\n elements[previousIndex].focus();\n activateOnFocus && elements[previousIndex].click();\n }\n\n break;\n }\n\n case 'ArrowUp': {\n if (orientation === 'vertical') {\n event.stopPropagation();\n event.preventDefault();\n elements[_previousIndex].focus();\n activateOnFocus && elements[_previousIndex].click();\n }\n\n break;\n }\n\n case 'ArrowDown': {\n if (orientation === 'vertical') {\n event.stopPropagation();\n event.preventDefault();\n elements[_nextIndex].focus();\n activateOnFocus && elements[_nextIndex].click();\n }\n\n break;\n }\n\n case 'Home': {\n event.stopPropagation();\n event.preventDefault();\n !elements[0].disabled && elements[0].focus();\n break;\n }\n\n case 'End': {\n event.stopPropagation();\n event.preventDefault();\n const last = elements.length - 1;\n !elements[last].disabled && elements[last].focus();\n break;\n }\n }\n };\n}\n"],"mappings":";;;AAEA,SAAS,iBAAiB,SAAiB,UAA+B,MAAe;AACvF,MAAK,IAAI,IAAI,UAAU,GAAG,KAAK,GAAG,KAAK,EACrC,KAAI,CAAC,SAAS,GAAG,SACf,QAAO;AAIX,KAAI;OACG,IAAI,IAAI,SAAS,SAAS,GAAG,IAAI,IAAI,KAAK,EAC7C,KAAI,CAAC,SAAS,GAAG,SACf,QAAO;;AAKb,QAAO;;AAGT,SAAS,aAAa,SAAiB,UAA+B,MAAe;AACnF,MAAK,IAAI,IAAI,UAAU,GAAG,IAAI,SAAS,QAAQ,KAAK,EAClD,KAAI,CAAC,SAAS,GAAG,SACf,QAAO;AAIX,KAAI;OACG,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,EACxC,KAAI,CAAC,SAAS,GAAG,SACf,QAAO;;AAKb,QAAO;;;AAIT,SAAS,YACP,QACA,SACA,gBACA;AACA,QACEA,8BAAAA,oBAAoB,QAAQ,eAAe,KAAKA,8BAAAA,oBAAoB,SAAS,eAAe;;AA2BhG,SAAgB,2BAA2B,EACzC,gBACA,iBACA,WACA,OAAO,MACP,kBAAkB,OAClB,MAAM,OACN,eAC2B;AAC3B,SAAQ,UAAkD;AACxD,cAAY,MAAM;EAElB,MAAM,WAAW,MAAM,KACrBA,8BAAAA,oBAAoB,MAAM,eAAe,eAAe,EAAE,iBACxD,gBACD,IAAI,EAAE,CACR,CAAC,QAAQ,SAAS,YAAY,MAAM,eAAe,MAAM,eAAe,CAAC;EAE1E,MAAM,UAAU,SAAS,WAAW,OAAO,MAAM,kBAAkB,GAAG;EACtE,MAAM,aAAa,aAAa,SAAS,UAAU,KAAK;EACxD,MAAM,iBAAiB,iBAAiB,SAAS,UAAU,KAAK;EAChE,MAAM,YAAY,QAAQ,QAAQ,iBAAiB;EACnD,MAAM,gBAAgB,QAAQ,QAAQ,aAAa;AAEnD,UAAQ,MAAM,KAAd;GACE,KAAK;AACH,QAAI,gBAAgB,cAAc;AAChC,WAAM,iBAAiB;AACvB,WAAM,gBAAgB;AACtB,cAAS,WAAW,OAAO;AAC3B,wBAAmB,SAAS,WAAW,OAAO;;AAGhD;GAGF,KAAK;AACH,QAAI,gBAAgB,cAAc;AAChC,WAAM,iBAAiB;AACvB,WAAM,gBAAgB;AACtB,cAAS,eAAe,OAAO;AAC/B,wBAAmB,SAAS,eAAe,OAAO;;AAGpD;GAGF,KAAK;AACH,QAAI,gBAAgB,YAAY;AAC9B,WAAM,iBAAiB;AACvB,WAAM,gBAAgB;AACtB,cAAS,gBAAgB,OAAO;AAChC,wBAAmB,SAAS,gBAAgB,OAAO;;AAGrD;GAGF,KAAK;AACH,QAAI,gBAAgB,YAAY;AAC9B,WAAM,iBAAiB;AACvB,WAAM,gBAAgB;AACtB,cAAS,YAAY,OAAO;AAC5B,wBAAmB,SAAS,YAAY,OAAO;;AAGjD;GAGF,KAAK;AACH,UAAM,iBAAiB;AACvB,UAAM,gBAAgB;AACtB,KAAC,SAAS,GAAG,YAAY,SAAS,GAAG,OAAO;AAC5C;GAGF,KAAK,OAAO;AACV,UAAM,iBAAiB;AACvB,UAAM,gBAAgB;IACtB,MAAM,OAAO,SAAS,SAAS;AAC/B,KAAC,SAAS,MAAM,YAAY,SAAS,MAAM,OAAO;AAClD"}