index.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import React, { ReactNode } from 'react';
  2. import classNames from 'classnames';
  3. import PropTypes from 'prop-types';
  4. import HotKeysFoudation, { HotKeysAdapter } from '@douyinfe/semi-foundation/hotKeys/foundation';
  5. import { cssClasses, Keys } from '@douyinfe/semi-foundation/hotKeys/constants';
  6. import BaseComponent from '../_base/baseComponent';
  7. import { noop } from 'lodash';
  8. import '@douyinfe/semi-foundation/hotKeys/hotKeys.scss';
  9. const prefixCls = cssClasses.PREFIX;
  10. export interface HotKeysProps {
  11. preventDefault?: boolean;
  12. hotKeys?: KeyboardEvent["key"][];
  13. content?: string[];
  14. onClick?: () => void;
  15. onHotKey?: (e: KeyboardEvent) => void;
  16. mergeMetaCtrl?: boolean;
  17. render?: () => ReactNode | ReactNode;
  18. getListenerTarget?: () => HTMLElement;
  19. className?: string;
  20. style?: React.CSSProperties
  21. }
  22. export interface HotKeysState {
  23. }
  24. class HotKeys extends BaseComponent<HotKeysProps, HotKeysState> {
  25. static propTypes = {
  26. preventDefault: PropTypes.bool,
  27. hotKeys: PropTypes.arrayOf(PropTypes.string),
  28. content: PropTypes.arrayOf(PropTypes.string),
  29. onClick: PropTypes.func,
  30. onHotKey: PropTypes.func,
  31. mergeMetaCtrl: PropTypes.bool,
  32. render: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
  33. getListenerTarget: PropTypes.func,
  34. className: PropTypes.string,
  35. style: PropTypes.object,
  36. };
  37. static defaultProps: Partial<HotKeysProps> = {
  38. preventDefault: false,
  39. hotKeys: null,
  40. content: null,
  41. onClick: noop,
  42. onHotKey: noop,
  43. mergeMetaCtrl: false,
  44. render: undefined,
  45. getListenerTarget: () => document.body,
  46. className: '',
  47. style: null,
  48. };
  49. static Keys = Keys
  50. constructor(props: HotKeysProps) {
  51. super(props);
  52. this.state = {
  53. };
  54. this.foundation = new HotKeysFoudation(this.adapter);
  55. }
  56. componentDidMount() {
  57. this.foundation.init();
  58. }
  59. componentDidUpdate(_prevProps: HotKeysProps) {
  60. }
  61. componentWillUnmount() {
  62. this.foundation.destroy();
  63. }
  64. foundation: HotKeysFoudation;
  65. get adapter(): HotKeysAdapter<HotKeysProps, HotKeysState> {
  66. return {
  67. ...super.adapter,
  68. notifyHotKey: (e: KeyboardEvent) => {
  69. this.props.onHotKey?.(e);
  70. },
  71. registerEvent: () => {
  72. let target = this.props.getListenerTarget?.() ?? document.body;
  73. target.addEventListener('keydown', this.foundation.handleKeyDown);
  74. },
  75. unregisterEvent: () => {
  76. let target = this.props.getListenerTarget?.() ?? document.body;
  77. target.removeEventListener('keydown', this.foundation.handleKeyDown);
  78. }
  79. };
  80. }
  81. render() {
  82. const { hotKeys, content, onClick, render, getListenerTarget, className, style, ...rest } = this.props;
  83. if (typeof render !== 'undefined') {
  84. if (render === null || (typeof render === 'function' && render() === null)) {
  85. return null;
  86. }
  87. return (
  88. <div
  89. onClick={onClick}
  90. className={classNames(prefixCls, className)}
  91. style={style}
  92. {...this.getDataAttr(rest)}
  93. >
  94. { typeof render === 'function' ? render() : render }
  95. </div>
  96. );
  97. }
  98. const renderContent = content ?? hotKeys;
  99. return (
  100. <div
  101. onClick={onClick}
  102. className={classNames(prefixCls, className)}
  103. style={style}
  104. {...this.getDataAttr(rest)}
  105. >
  106. {renderContent.map((key: KeyboardEvent["key"], index) => {
  107. return index === 0 ?
  108. (<span key={index}>
  109. <span className={prefixCls + '-content'}>{key}</span>
  110. </span>)
  111. :
  112. (<span key={index}>
  113. <span className={prefixCls + '-split'}>+</span>
  114. <span className={prefixCls + '-content'}>{key}</span>
  115. </span>);
  116. })}
  117. </div>
  118. );
  119. }
  120. }
  121. export default HotKeys;