@antscorp/antsomi-ui 1.3.5-beta.907 → 1.3.5-beta.909

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.
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import type { PayloadInfo } from '@antscorp/antsomi-ui/es/types';
3
2
  export type TDisplayFormat = 'number' | 'percentage' | 'currency' | 'datetime';
4
3
  type DisplayFormatProps = {
@@ -16,7 +16,7 @@ import '@yaireo/tagify/dist/tagify.css';
16
16
  // Styled
17
17
  import { TagTextArea, TagifyWrapper, WrapperPlaceHolder } from './styled';
18
18
  // Utils
19
- import { parseTagStringToTagify, convertInputStringToOriginal, emojiManufacturer, getEmojiTag, isPersonalizeTagType, generateTagContent, unescapeString, hasLineBreak, selectRange, isTagClickable, findURLInTextNodes, getAttributesString, } from './utils';
19
+ import { parseTagStringToTagify, convertInputStringToOriginal, emojiManufacturer, getEmojiTag, isPersonalizeTagType, generateTagContent, unescapeString, hasLineBreak, selectRange, isTagClickable, findURLInTextNodes, getAttributesString, isAnchorNodeChildOfElement, } from './utils';
20
20
  import { acceptablePatternChecking, detectURLRegex, getCachedRegex, getPersonalizeTagInfo, patternHandlers, } from './patternHandlers';
21
21
  // Constants
22
22
  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, defaultCssVariables, tagifyDefaultProps, } from './constants';
@@ -80,8 +80,15 @@ const TagifyInput = forwardRef((props, ref) => {
80
80
  }, []);
81
81
  const onSelectionAfterInjection = useCallback((addRangeAfterInjected) => {
82
82
  try {
83
- const selection = window.getSelection();
84
- if (selection?.rangeCount) {
83
+ if (!tagifyRef.current) {
84
+ throw new Error('Tagify instance is not initialized');
85
+ }
86
+ const { scope } = tagifyRef.current?.DOM;
87
+ const isValidSelection = isAnchorNodeChildOfElement(scope);
88
+ if (isValidSelection) {
89
+ const selection = window.getSelection();
90
+ if (!selection?.rangeCount)
91
+ return;
85
92
  const range = selection.getRangeAt(0);
86
93
  if (addRangeAfterInjected) {
87
94
  // Need to re-select to keep the caret position
@@ -107,9 +114,10 @@ const TagifyInput = forwardRef((props, ref) => {
107
114
  const { settings, DOM } = tagifyRef.current;
108
115
  const rangeInstance = _.get(tagifyRef.current, 'state.selection.range', null);
109
116
  const { empty } = settings.classNames;
117
+ const isValidSelection = isAnchorNodeChildOfElement(DOM.scope);
110
118
  const selection = window.getSelection();
111
119
  // In case not have the selection yet or lost the selection,
112
- if (!selection?.rangeCount || !rangeInstance) {
120
+ if (!selection?.rangeCount || !isValidSelection || !rangeInstance) {
113
121
  // need to restore the last range before inject a new tag if the last range exists
114
122
  if (lastRange.current) {
115
123
  selection?.removeAllRanges();
@@ -67,6 +67,7 @@ export declare const generateTagContent: (params: {
67
67
  * // returns 'Hello "world" with spaces'
68
68
  */
69
69
  export declare const unescapeString: (str: string) => string;
70
+ export declare function deepUnescape<T = any>(obj: T): T | string;
70
71
  /**
71
72
  * Checks if the string is a valid tag type.
72
73
  * @param str
@@ -173,3 +174,11 @@ export declare function findURLInTextNodes(element: HTMLSpanElement, minLengthVa
173
174
  * // Returns: 'class="btn-primary" disabled data-testid="submit-button" aria-label="Submit form" tabindex="0"'
174
175
  */
175
176
  export declare const getAttributesString: (map: Map<string, string | boolean | number>) => string;
177
+ /**
178
+ * Checks if the anchor node of the current text selection
179
+ * is a child of a specific DOM element.
180
+ *
181
+ * @param {HTMLElement} element - The parent element to check against
182
+ * @returns {boolean} True if the anchor node is a child of the element, false otherwise
183
+ */
184
+ export declare const isAnchorNodeChildOfElement: (element: Node) => boolean;
@@ -447,6 +447,21 @@ export const unescapeString = (str) => str.replace(/&quot;|&nbsp;|nbsp;|&#x27;/g
447
447
  return match;
448
448
  }
449
449
  });
450
+ export function deepUnescape(obj) {
451
+ // Base case: Return primitives as is
452
+ if (obj === null || typeof obj !== 'object') {
453
+ return typeof obj === 'string' ? unescapeString(obj) : obj;
454
+ }
455
+ // Handle arrays: Map and recurse
456
+ if (Array.isArray(obj)) {
457
+ return obj.map(deepUnescape);
458
+ }
459
+ // Handle objects: Recurse into key-value pairs
460
+ return Object.entries(obj).reduce((result, [key, value]) => {
461
+ result[key] = deepUnescape(value);
462
+ return result;
463
+ }, {});
464
+ }
450
465
  /**
451
466
  * Checks if the string is a valid tag type.
452
467
  * @param str
@@ -602,3 +617,26 @@ export const getAttributesString = (map) => Array.from(map.entries())
602
617
  })
603
618
  .filter(Boolean)
604
619
  .join(' ');
620
+ /**
621
+ * Checks if the anchor node of the current text selection
622
+ * is a child of a specific DOM element.
623
+ *
624
+ * @param {HTMLElement} element - The parent element to check against
625
+ * @returns {boolean} True if the anchor node is a child of the element, false otherwise
626
+ */
627
+ export const isAnchorNodeChildOfElement = (element) => {
628
+ // Get the current selection
629
+ const selection = window.getSelection();
630
+ // Check if there's an active selection
631
+ if (!selection || selection.rangeCount === 0) {
632
+ return false;
633
+ }
634
+ // Get the anchor node (where the selection starts)
635
+ const { anchorNode } = selection;
636
+ // Check if the anchor node exists and the element exists
637
+ if (!anchorNode || !element) {
638
+ return false;
639
+ }
640
+ // Use Node.contains() to check if the element contains the anchor node
641
+ return element.contains(anchorNode);
642
+ };
@@ -3,5 +3,4 @@
3
3
  * Asynchronously loads the component for TemplateListing
4
4
  *
5
5
  */
6
- /// <reference types="react" />
7
6
  export declare const TemplateListing: (props: import("./types").TemplateListingProps<{}>) => JSX.Element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antscorp/antsomi-ui",
3
- "version": "1.3.5-beta.907",
3
+ "version": "1.3.5-beta.909",
4
4
  "description": "An enterprise-class UI design language and React UI library.",
5
5
  "sideEffects": [
6
6
  "dist/*",