@antscorp/antsomi-ui 2.0.78 → 2.0.80

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.
@@ -126,5 +126,5 @@ export const DrawerDetail = props => {
126
126
  onClose(e);
127
127
  }, children: _jsx(Icon, { type: "icon-ants-remove-slim", size: 14 }) })), showExpandButton && !fullScreen && (_jsx(ToggleDrawerSizeButton, { style: {
128
128
  ...(!showMenu && { background: '#ffffff' }),
129
- }, onClick: () => handleToggleDrawerSize(), collapse: collapseDrawer })), showMenu && (_jsxs(LeftMenu, { "data-test": "left-menu", className: "animate__animated animate__fadeIn", children: [_jsxs("div", { children: [showClose && (_jsx(CloseBtn, { "data-test": "close-btn", onClick: onClose, children: _jsx(Icon, { type: "icon-ants-remove-slim", size: 14 }) })), _jsx(Flex, { vertical: true, gap: 10, align: "center", justify: "center", children: items?.map((item) => (_jsx(Tooltip, { title: item?.label, mouseEnterDelay: 0.3, placement: "right", children: _jsx(MenuItem, { className: selectedKeys?.includes(item.key) ? 'active' : '', onClick: () => onClick && onClick(item), children: item.icon }, item?.key) }, item?.key))) })] }), _jsx(MenuFooter, { children: footer })] })), _jsxs(Content, { className: "drawer-detail-content", children: [headerProps?.children && (_jsx(DrawerHeader, { align: "center", ...restOfHeaderProps, children: headerChildren })), children] })] }));
129
+ }, onClick: () => handleToggleDrawerSize(), collapse: collapseDrawer })), showMenu && (_jsxs(LeftMenu, { "data-test": "left-menu", className: "animate__animated animate__fadeIn", children: [_jsxs("div", { children: [showClose && (_jsx(CloseBtn, { "data-test": "close-btn", ...restOfCloseIcon, onClick: onClose, children: _jsx(Icon, { type: "icon-ants-remove-slim", size: 14 }) })), _jsx(Flex, { vertical: true, gap: 10, align: "center", justify: "center", children: items?.map((item) => (_jsx(Tooltip, { title: item?.label, mouseEnterDelay: 0.3, placement: "right", children: _jsx(MenuItem, { className: selectedKeys?.includes(item.key) ? 'active' : '', onClick: () => onClick && onClick(item), children: item.icon }, item?.key) }, item?.key))) })] }), _jsx(MenuFooter, { children: footer })] })), _jsxs(Content, { className: "drawer-detail-content", children: [headerProps?.children && (_jsx(DrawerHeader, { align: "center", ...restOfHeaderProps, children: headerChildren })), children] })] }));
130
130
  };
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /* eslint-disable react-hooks/exhaustive-deps */
2
3
  // Libraries
3
4
  import { useRef, useEffect, useCallback, useMemo, memo, forwardRef, useImperativeHandle, useLayoutEffect, useState, } from 'react';
4
5
  import _ from 'lodash';
@@ -16,7 +17,7 @@ import '@yaireo/tagify/dist/tagify.css';
16
17
  // Styled
17
18
  import { TagTextArea, TagifyWrapper, WrapperPlaceHolder } from './styled';
18
19
  // Utils
19
- import { parseTagStringToTagify, convertInputStringToOriginal, emojiManufacturer, getEmojiTag, isPersonalizeTagType, generateTagContent, unescapeString, hasLineBreak, selectRange, isTagClickable, findURLInTextNodes, getAttributesString, isAnchorNodeChildOfElement, isShortLinkTagType, } from './utils';
20
+ import { parseTagStringToTagify, convertInputStringToOriginal, emojiManufacturer, getEmojiTag, isPersonalizeTagType, generateTagContent, unescapeString, hasLineBreak, selectRange, isTagClickable, findURLInTextNodes, getAttributesString, isAnchorNodeChildOfElement, isShortLinkTagType, isCaretAtEndOfTextNodeWithNextTag, } from './utils';
20
21
  import { acceptablePatternChecking, detectURLRegex, getCachedRegex, getPersonalizeTagInfo, getShortLinkTagInfo, patternHandlers, } from './patternHandlers';
21
22
  // Constants
22
23
  import { DETECT_LINK, EMOJI, FORCE_SHOW_TOOLTIP, INVALID_TAG, MESSAGE_TAG, NO_VIEW_TAG, PERSONALIZE_PTN, PROMOTION_CODE, READONLY_TAG, REMOVED_TAG, SHORT_LINK, SHORT_LINK_PTN, SHORT_LINK_V2, defaultCssVariables, tagifyDefaultProps, } from './constants';
@@ -47,6 +48,12 @@ const TagifyInput = forwardRef((props, ref) => {
47
48
  return content;
48
49
  // eslint-disable-next-line react-hooks/exhaustive-deps
49
50
  }, []);
51
+ const onInputDebounceCallback = useCallback(_.debounce((callback, event) => {
52
+ callback(event);
53
+ }, 350), []);
54
+ const onChangeDebounceCallback = useCallback(_.debounce((callback, event) => {
55
+ callback(event);
56
+ }, 500), []);
50
57
  const onSyncSelectionStateTagify = useCallback(() => {
51
58
  try {
52
59
  if (!tagifyRef.current) {
@@ -455,6 +462,10 @@ const TagifyInput = forwardRef((props, ref) => {
455
462
  }
456
463
  }
457
464
  }, [realtime, detectReplaceURLToTag, onOutputData]);
465
+ const onInputTagifyDebounce = useCallback(_.partial(onInputDebounceCallback, onTagifyTyping), [
466
+ onInputDebounceCallback,
467
+ onTagifyTyping,
468
+ ]);
458
469
  /**
459
470
  * Capture to trigger when tagify changed
460
471
  */
@@ -469,6 +480,22 @@ const TagifyInput = forwardRef((props, ref) => {
469
480
  onOutputData(convertedValue);
470
481
  }
471
482
  }, [onOutputData]);
483
+ const onTagifyChangedDebounce = useCallback(_.partial(onChangeDebounceCallback, onTagifyChanged), [onTagifyChanged, onChangeDebounceCallback]);
484
+ const onKeyDown = useCallback((e) => {
485
+ if (e.detail.event.key !== 'Enter' ||
486
+ e.detail.event.shiftKey ||
487
+ !isCaretAtEndOfTextNodeWithNextTag())
488
+ return;
489
+ const selection = window.getSelection();
490
+ if (!selection?.rangeCount)
491
+ return;
492
+ const range = selection.getRangeAt(0);
493
+ const currentNode = range.endContainer;
494
+ const cacheEndOffset = range.endOffset;
495
+ currentNode.textContent += ' ';
496
+ range.setEnd(currentNode, cacheEndOffset);
497
+ range.collapse(false);
498
+ }, []);
472
499
  const customizeTag = useCallback((tagData, tagify) => {
473
500
  const { value, collection, label, type } = tagData;
474
501
  const { settings } = tagify;
@@ -791,28 +818,22 @@ const TagifyInput = forwardRef((props, ref) => {
791
818
  // Listen to Tagify events
792
819
  useEffect(() => {
793
820
  const { current: tagifyInstance } = tagifyRef || {};
794
- let onInputTagifyDebounce;
795
- let onTagifyChangedDebounce;
796
821
  if (tagifyInstance) {
797
- onInputTagifyDebounce = _.debounce(onTagifyTyping, 350);
798
- onTagifyChangedDebounce = _.debounce(onTagifyChanged, 500);
799
822
  tagifyInstance.on('click', onTagItemClick);
800
823
  tagifyInstance.on('input', onInputTagifyDebounce);
801
824
  tagifyInstance.on('change', onTagifyChangedDebounce);
825
+ tagifyInstance.on('keydown', onKeyDown);
802
826
  }
803
827
  // Off listen to Tagify events
804
828
  return () => {
805
829
  if (tagifyInstance) {
806
830
  tagifyInstance.off('click', onTagItemClick);
807
- if (onInputTagifyDebounce) {
808
- tagifyInstance.off('input', onInputTagifyDebounce);
809
- }
810
- if (onTagifyChangedDebounce) {
811
- tagifyInstance.off('change', onTagifyChangedDebounce);
812
- }
831
+ tagifyInstance.off('input', onInputTagifyDebounce);
832
+ tagifyInstance.off('change', onTagifyChangedDebounce);
833
+ tagifyInstance.off('keydown', onKeyDown);
813
834
  }
814
835
  };
815
- }, [onTagItemClick, onTagifyTyping, onTagifyChanged]);
836
+ }, [onTagItemClick, onInputTagifyDebounce, onTagifyChangedDebounce, onKeyDown]);
816
837
  // At the first render, need to update URL to tag to show hint in the tooltip with tag
817
838
  useEffect(() => {
818
839
  detectReplaceURLToTag();
@@ -1,5 +1,5 @@
1
1
  /// <reference types="yaireo__tagify" />
2
- import { ClassNameSettings, TagData, TagifySettings } from '@yaireo/tagify';
2
+ import Tagify, { ClassNameSettings, TagData, TagifySettings } from '@yaireo/tagify';
3
3
  import { EMOJI_COLLECTIONS, PATTERN_CACHE_TYPE, SHORT_LINK_TYPE, TAG_TYPE } from './constants';
4
4
  import { type CSSProperties } from 'react';
5
5
  export type MapAttributesProps = Record<string, Record<string, any>>;
@@ -196,3 +196,4 @@ export interface TagifyWrapperProps {
196
196
  $placeholder?: string;
197
197
  $isSingleLineText?: TagifyInputProps['isSingleLineText'];
198
198
  }
199
+ export type CustomEventTagify = CustomEvent<Tagify.InputEventData<TagDataCustomize>> | CustomEvent<Tagify.ChangeEventData<TagDataCustomize>>;
@@ -184,3 +184,4 @@ export declare const getAttributesString: (map: Map<string, string | boolean | n
184
184
  * @returns {boolean} True if the anchor node is a child of the element, false otherwise
185
185
  */
186
186
  export declare const isAnchorNodeChildOfElement: (element: Node, anchorNodeInstance: Node | null) => boolean;
187
+ export declare function isCaretAtEndOfTextNodeWithNextTag(): boolean;
@@ -649,3 +649,22 @@ export const isAnchorNodeChildOfElement = (element, anchorNodeInstance) => {
649
649
  // Use Node.contains() to check if the element contains the anchor node
650
650
  return element.contains(anchorNode) && element.contains(anchorNodeInstance);
651
651
  };
652
+ export function isCaretAtEndOfTextNodeWithNextTag() {
653
+ const selection = window.getSelection();
654
+ if (!selection || selection.rangeCount === 0)
655
+ return false;
656
+ const range = selection.getRangeAt(0);
657
+ const { startContainer, startOffset } = range;
658
+ // Check if caret is inside a text node
659
+ if (startContainer.nodeType !== Node.TEXT_NODE)
660
+ return false;
661
+ const textNode = startContainer;
662
+ // Check if caret is at the end of the text node
663
+ if (startOffset !== textNode.length)
664
+ return false;
665
+ // Now check if the next sibling is a tag (element node)
666
+ const { nextSibling } = textNode;
667
+ if (!nextSibling)
668
+ return false;
669
+ return nextSibling.nodeType === Node.ELEMENT_NODE && nextSibling.nodeName === 'TAG';
670
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antscorp/antsomi-ui",
3
- "version": "2.0.78",
3
+ "version": "2.0.80",
4
4
  "description": "An enterprise-class UI design language and React UI library.",
5
5
  "sideEffects": [
6
6
  "dist/*",