@capillarytech/creatives-library 9.0.4 → 9.0.5

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "9.0.4",
4
+ "version": "9.0.5",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -77,7 +77,7 @@ export const MessageSection = ({
77
77
  // <textarea> by id and feed it to the existing ref handler. CapEmojiPicker and
78
78
  // the Aira trigger both read `messageTextAreaRef.current` as that DOM node.
79
79
  useEffect(() => {
80
- handleMessageTextAreaRef(document.getElementById('webpush-message-input'));
80
+ handleMessageTextAreaRef(document?.getElementById('webpush-message-input'));
81
81
  }, [handleMessageTextAreaRef]);
82
82
 
83
83
  const renderCharacterCount = () => {
@@ -152,7 +152,7 @@ MessageSection.propTypes = {
152
152
  tagList: PropTypes.node,
153
153
  messageCountRef: PropTypes.object,
154
154
  messageTextAreaRef: PropTypes.object,
155
- handleMessageTextAreaRef: PropTypes.func.isRequired,
155
+ handleMessageTextAreaRef: PropTypes.func,
156
156
  isAiContentBotDisabled: PropTypes.bool,
157
157
  };
158
158
 
@@ -161,6 +161,7 @@ MessageSection.defaultProps = {
161
161
  tagList: null,
162
162
  messageCountRef: null,
163
163
  messageTextAreaRef: null,
164
+ handleMessageTextAreaRef: () => {},
164
165
  isAiContentBotDisabled: false,
165
166
  };
166
167
 
@@ -700,6 +700,147 @@ describe('PreviewControls', () => {
700
700
  });
701
701
  });
702
702
 
703
+ describe('getPopupContainer (getDropdownPopupContainer)', () => {
704
+ const getResolver = (wrapper) =>
705
+ wrapper.find(CapSelect.CapCustomSelect).first().prop('getPopupContainer');
706
+
707
+ let appended;
708
+
709
+ beforeEach(() => {
710
+ appended = [];
711
+ });
712
+
713
+ afterEach(() => {
714
+ // Keep jsdom clean between assertions so containers from one test don't leak
715
+ appended.forEach((node) => {
716
+ if (node && node.parentNode) {
717
+ node.parentNode.removeChild(node);
718
+ }
719
+ });
720
+ appended = [];
721
+ });
722
+
723
+ const mountInBody = (node) => {
724
+ document.body.appendChild(node);
725
+ appended.push(node);
726
+ return node;
727
+ };
728
+
729
+ it('should pass getPopupContainer to every rendered select', () => {
730
+ const wrapper = mountWithIntl(<PreviewControls {...defaultProps} showStateDropdown={true} />);
731
+ const selects = wrapper.find(CapSelect.CapCustomSelect);
732
+ expect(selects.length).toBe(3);
733
+ selects.forEach((select) => {
734
+ expect(typeof select.prop('getPopupContainer')).toBe('function');
735
+ });
736
+ });
737
+
738
+ it('should return the closest .ant-modal-container ancestor when one exists', () => {
739
+ const wrapper = mountWithIntl(<PreviewControls {...defaultProps} />);
740
+ const getPopupContainer = getResolver(wrapper);
741
+
742
+ const modalContainer = document.createElement('div');
743
+ modalContainer.className = 'ant-modal-container';
744
+ const triggerNode = document.createElement('span');
745
+ modalContainer.appendChild(triggerNode);
746
+ mountInBody(modalContainer);
747
+
748
+ expect(getPopupContainer(triggerNode)).toBe(modalContainer);
749
+ });
750
+
751
+ it('should return the closest .ant-modal-content ancestor when one exists', () => {
752
+ const wrapper = mountWithIntl(<PreviewControls {...defaultProps} />);
753
+ const getPopupContainer = getResolver(wrapper);
754
+
755
+ const modalContent = document.createElement('div');
756
+ modalContent.className = 'ant-modal-content';
757
+ const triggerNode = document.createElement('span');
758
+ modalContent.appendChild(triggerNode);
759
+ mountInBody(modalContent);
760
+
761
+ expect(getPopupContainer(triggerNode)).toBe(modalContent);
762
+ });
763
+
764
+ it('should resolve through deeply nested descendants up to the modal ancestor', () => {
765
+ const wrapper = mountWithIntl(<PreviewControls {...defaultProps} />);
766
+ const getPopupContainer = getResolver(wrapper);
767
+
768
+ const modalContainer = document.createElement('div');
769
+ modalContainer.className = 'ant-modal-container';
770
+ const middle = document.createElement('div');
771
+ const triggerNode = document.createElement('span');
772
+ middle.appendChild(triggerNode);
773
+ modalContainer.appendChild(middle);
774
+ mountInBody(modalContainer);
775
+
776
+ expect(getPopupContainer(triggerNode)).toBe(modalContainer);
777
+ });
778
+
779
+ it('should match the trigger node itself when it is the modal container', () => {
780
+ const wrapper = mountWithIntl(<PreviewControls {...defaultProps} />);
781
+ const getPopupContainer = getResolver(wrapper);
782
+
783
+ const modalContainer = document.createElement('div');
784
+ modalContainer.className = 'ant-modal-content';
785
+ mountInBody(modalContainer);
786
+
787
+ // closest() includes the element itself, so a self-match should be returned
788
+ expect(getPopupContainer(modalContainer)).toBe(modalContainer);
789
+ });
790
+
791
+ it('should pick the nearest modal ancestor when modals are nested', () => {
792
+ const wrapper = mountWithIntl(<PreviewControls {...defaultProps} />);
793
+ const getPopupContainer = getResolver(wrapper);
794
+
795
+ const outerModal = document.createElement('div');
796
+ outerModal.className = 'ant-modal-container';
797
+ const innerModal = document.createElement('div');
798
+ innerModal.className = 'ant-modal-content';
799
+ const triggerNode = document.createElement('span');
800
+ innerModal.appendChild(triggerNode);
801
+ outerModal.appendChild(innerModal);
802
+ mountInBody(outerModal);
803
+
804
+ expect(getPopupContainer(triggerNode)).toBe(innerModal);
805
+ });
806
+
807
+ it('should fall back to document.body when the trigger is not inside a modal', () => {
808
+ const wrapper = mountWithIntl(<PreviewControls {...defaultProps} />);
809
+ const getPopupContainer = getResolver(wrapper);
810
+
811
+ const wrapperDiv = document.createElement('div');
812
+ wrapperDiv.className = 'some-unrelated-container';
813
+ const triggerNode = document.createElement('span');
814
+ wrapperDiv.appendChild(triggerNode);
815
+ mountInBody(wrapperDiv);
816
+
817
+ expect(getPopupContainer(triggerNode)).toBe(document.body);
818
+ });
819
+
820
+ it('should fall back to document.body for a detached (unattached) trigger node', () => {
821
+ const wrapper = mountWithIntl(<PreviewControls {...defaultProps} />);
822
+ const getPopupContainer = getResolver(wrapper);
823
+
824
+ const detachedNode = document.createElement('span');
825
+ expect(getPopupContainer(detachedNode)).toBe(document.body);
826
+ });
827
+
828
+ it('should resolve the same way for the compact layout selects', () => {
829
+ const wrapper = mountWithIntl(
830
+ <PreviewControls {...defaultProps} layoutMode={LAYOUT_MODE.COMPACT} showStateDropdown={true} />,
831
+ );
832
+ const getPopupContainer = getResolver(wrapper);
833
+
834
+ const modalContainer = document.createElement('div');
835
+ modalContainer.className = 'ant-modal-container';
836
+ const triggerNode = document.createElement('span');
837
+ modalContainer.appendChild(triggerNode);
838
+ mountInBody(modalContainer);
839
+
840
+ expect(getPopupContainer(triggerNode)).toBe(modalContainer);
841
+ });
842
+ });
843
+
703
844
  describe('FormattedMessage Integration', () => {
704
845
  it('should render FormattedMessage for operatingSystem label', () => {
705
846
  const wrapper = mountWithIntl(<PreviewControls {...defaultProps} />);
@@ -21,6 +21,7 @@ exports[`PreviewControls Basic Rendering should render correctly with default pr
21
21
  />
22
22
  </CapLabel>
23
23
  <ComponentWithLabel(InjectIntl(CapCustomSelect))
24
+ getPopupContainer={[Function]}
24
25
  onChange={[Function]}
25
26
  options={
26
27
  Array [
@@ -70,6 +71,7 @@ exports[`PreviewControls Basic Rendering should render correctly with default pr
70
71
  />
71
72
  </CapLabel>
72
73
  <ComponentWithLabel(InjectIntl(CapCustomSelect))
74
+ getPopupContainer={[Function]}
73
75
  onChange={[Function]}
74
76
  options={
75
77
  Array [
@@ -119,6 +121,7 @@ exports[`PreviewControls Basic Rendering should render correctly with default pr
119
121
  />
120
122
  </CapLabel>
121
123
  <ComponentWithLabel(InjectIntl(CapCustomSelect))
124
+ getPopupContainer={[Function]}
122
125
  onChange={[MockFunction]}
123
126
  options={
124
127
  Array [