subNavFoundation.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import BaseFoundation, { DefaultAdapter } from '../base/foundation';
  2. import isEnterPress from '../utils/isEnterPress';
  3. const addKeys = function addKeys(originKeys: (string | number)[] = [], ...willAddKeys: (string | number)[]) {
  4. const keySet = new Set(originKeys);
  5. willAddKeys.forEach(key => key && keySet.add(key));
  6. return Array.from(keySet);
  7. };
  8. const removeKeys = function removeKeys(originKeys: (string | number)[] = [], ...willRemoveKeys: (string | number)[]) {
  9. const keySet = new Set(originKeys);
  10. willRemoveKeys.forEach(key => key && keySet.delete(key));
  11. return Array.from(keySet);
  12. };
  13. export interface OnOpenChangeData {
  14. itemKey: string | number;
  15. openKeys: (string | number)[];
  16. isOpen: boolean;
  17. }
  18. export interface OnClickData extends OnOpenChangeData {
  19. domEvent: any;
  20. }
  21. export interface OnSelectData extends OnOpenChangeData {
  22. domEvent: any;
  23. }
  24. export interface SubNavAdapter<P = Record<string, any>, S = Record<string, any>> extends DefaultAdapter<P, S> {
  25. updateIsHovered(isHovered: boolean): void;
  26. getOpenKeys(): (string | number)[];
  27. getOpenKeysIsControlled(): boolean;
  28. getCanUpdateOpenKeys(): boolean;
  29. updateOpen(isOpen: boolean): void;
  30. notifyGlobalOpenChange(data: OnOpenChangeData): void;
  31. notifyGlobalOnSelect(data: OnSelectData): void;
  32. notifyGlobalOnClick(data: OnClickData): void;
  33. getIsSelected(itemKey: string | number): boolean;
  34. getIsOpen(): boolean;
  35. }
  36. export default class SubNavFoundation<P = Record<string, any>, S = Record<string, any>> extends BaseFoundation<SubNavAdapter<P, S>, P, S> {
  37. constructor(adapter: SubNavAdapter<P, S>) {
  38. super({ ...adapter });
  39. }
  40. _timer: number;
  41. init() {
  42. // this.log('invoke SubNavFoundation init()');
  43. this._timer = null;
  44. }
  45. destroy() {} // eslint-disable-line
  46. clearDelayTimer() {
  47. if (this._timer) {
  48. clearTimeout(this._timer);
  49. this._timer = null;
  50. }
  51. }
  52. isValidKey(itemKey: string | number) {
  53. // eslint-disable-next-line eqeqeq
  54. return itemKey != null && (typeof itemKey === 'number' || typeof itemKey === 'string');
  55. }
  56. handleDropdownVisibleChange(visible: boolean) {
  57. const itemKey = this.getProp('itemKey');
  58. const openKeysIsControlled = this._adapter.getOpenKeysIsControlled();
  59. const canUpdateOpenKeys = this._adapter.getCanUpdateOpenKeys();
  60. const rawOpenKeys = this._adapter.getOpenKeys();
  61. const openKeys = visible ? addKeys(rawOpenKeys, itemKey) : removeKeys(rawOpenKeys, itemKey);
  62. this.clearDelayTimer();
  63. if (!openKeysIsControlled) {
  64. if (canUpdateOpenKeys) {
  65. this._adapter.updateOpen(visible);
  66. }
  67. // this._adapter.updateIsHovered(visible);
  68. }
  69. this._adapter.notifyGlobalOpenChange({ itemKey, openKeys, isOpen: visible });
  70. }
  71. /**
  72. *
  73. * @param {Event} e
  74. * @param {HTMLElement} titleRef
  75. */
  76. handleClick(e: any, titleRef: any) {
  77. const { itemKey, disabled } = this.getProps();
  78. if (disabled) {
  79. return;
  80. }
  81. // this.log(e, titleRef, titleRef.contains(e.target));
  82. const clickedDomIsTitle = titleRef && titleRef.contains(e.target);
  83. let isOpen = Boolean(this._adapter.getIsOpen());
  84. if (!clickedDomIsTitle) {
  85. isOpen = false;
  86. } else {
  87. isOpen = !isOpen;
  88. }
  89. const openKeys = isOpen
  90. ? addKeys(this._adapter.getOpenKeys(), itemKey)
  91. : removeKeys(this._adapter.getOpenKeys(), itemKey);
  92. const cbVal = { itemKey, openKeys, isOpen, domEvent: e };
  93. const openKeysIsControlled = this._adapter.getOpenKeysIsControlled();
  94. const canUpdateOpenKeys = this._adapter.getCanUpdateOpenKeys();
  95. if (!openKeysIsControlled && canUpdateOpenKeys) {
  96. this._adapter.updateOpen(isOpen);
  97. }
  98. this._adapter.notifyGlobalOpenChange(cbVal);
  99. this._adapter.notifyGlobalOnClick(cbVal);
  100. }
  101. /**
  102. * A11y: simulate sub nav click
  103. * @param e
  104. * @param titleRef
  105. */
  106. handleKeyPress(e: any, titleRef: any) {
  107. if (isEnterPress(e)) {
  108. this.handleClick(e, titleRef);
  109. }
  110. }
  111. }