@memori.ai/memori-react 8.11.0 → 8.12.0

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.
Files changed (169) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/dist/components/AgeVerificationModal/AgeVerificationModal.css +41 -14
  3. package/dist/components/AgeVerificationModal/AgeVerificationModal.js +2 -2
  4. package/dist/components/AgeVerificationModal/AgeVerificationModal.js.map +1 -1
  5. package/dist/components/Auth/Auth.js +36 -8
  6. package/dist/components/Auth/Auth.js.map +1 -1
  7. package/dist/components/Avatar/AvatarView/AvatarComponent/positionControls/positionControls.css +2 -2
  8. package/dist/components/Chat/Chat.js +2 -2
  9. package/dist/components/Chat/Chat.js.map +1 -1
  10. package/dist/components/ChatBubble/ChatBubble.css +81 -13
  11. package/dist/components/ChatBubble/ChatBubble.js +86 -19
  12. package/dist/components/ChatBubble/ChatBubble.js.map +1 -1
  13. package/dist/components/ChatHistoryDrawer/ChatHistory.css +5 -1
  14. package/dist/components/ChatInputs/ChatInputs.d.ts +1 -0
  15. package/dist/components/ChatInputs/ChatInputs.js +8 -3
  16. package/dist/components/ChatInputs/ChatInputs.js.map +1 -1
  17. package/dist/components/DateSelector/DateSelector.css +125 -104
  18. package/dist/components/DateSelector/DateSelector.d.ts +1 -1
  19. package/dist/components/DateSelector/DateSelector.js +110 -52
  20. package/dist/components/DateSelector/DateSelector.js.map +1 -1
  21. package/dist/components/Header/Header.js +1 -1
  22. package/dist/components/Header/Header.js.map +1 -1
  23. package/dist/components/LoginDrawer/LoginDrawer.css +37 -5
  24. package/dist/components/LoginDrawer/LoginDrawer.d.ts +1 -2
  25. package/dist/components/LoginDrawer/LoginDrawer.js +2 -9
  26. package/dist/components/LoginDrawer/LoginDrawer.js.map +1 -1
  27. package/dist/components/MediaWidget/MediaWidget.css +4 -0
  28. package/dist/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.js +1 -1
  29. package/dist/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.js.map +1 -1
  30. package/dist/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyButtonWithDropdown.js +1 -1
  31. package/dist/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyButtonWithDropdown.js.map +1 -1
  32. package/dist/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyMenuItem.js +3 -0
  33. package/dist/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyMenuItem.js.map +1 -1
  34. package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js +2 -2
  35. package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js.map +1 -1
  36. package/dist/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.css +16 -7
  37. package/dist/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js +6 -4
  38. package/dist/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js.map +1 -1
  39. package/dist/components/MemoriWidget/MemoriWidget.js +69 -25
  40. package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
  41. package/dist/components/UploadButton/UploadButton.js +2 -0
  42. package/dist/components/UploadButton/UploadButton.js.map +1 -1
  43. package/dist/components/UploadButton/UploadImages/UploadImages.js +2 -2
  44. package/dist/components/UploadButton/UploadImages/UploadImages.js.map +1 -1
  45. package/dist/components/ui/Drawer.css +8 -0
  46. package/dist/components/ui/Drawer.d.ts +2 -0
  47. package/dist/components/ui/Drawer.js +2 -2
  48. package/dist/components/ui/Drawer.js.map +1 -1
  49. package/dist/components/ui/Tooltip.css +49 -1
  50. package/dist/components/ui/Tooltip.d.ts +1 -1
  51. package/dist/locales/de.json +6 -1
  52. package/dist/locales/en.json +9 -1
  53. package/dist/locales/es.json +6 -1
  54. package/dist/locales/fr.json +5 -1
  55. package/dist/locales/it.json +8 -1
  56. package/dist/styles.css +3 -2
  57. package/esm/components/AgeVerificationModal/AgeVerificationModal.css +41 -14
  58. package/esm/components/AgeVerificationModal/AgeVerificationModal.js +2 -2
  59. package/esm/components/AgeVerificationModal/AgeVerificationModal.js.map +1 -1
  60. package/esm/components/Auth/Auth.js +36 -8
  61. package/esm/components/Auth/Auth.js.map +1 -1
  62. package/esm/components/Avatar/AvatarView/AvatarComponent/positionControls/positionControls.css +2 -2
  63. package/esm/components/Chat/Chat.js +2 -2
  64. package/esm/components/Chat/Chat.js.map +1 -1
  65. package/esm/components/ChatBubble/ChatBubble.css +81 -13
  66. package/esm/components/ChatBubble/ChatBubble.js +87 -20
  67. package/esm/components/ChatBubble/ChatBubble.js.map +1 -1
  68. package/esm/components/ChatHistoryDrawer/ChatHistory.css +5 -1
  69. package/esm/components/ChatInputs/ChatInputs.d.ts +1 -0
  70. package/esm/components/ChatInputs/ChatInputs.js +8 -3
  71. package/esm/components/ChatInputs/ChatInputs.js.map +1 -1
  72. package/esm/components/DateSelector/DateSelector.css +125 -104
  73. package/esm/components/DateSelector/DateSelector.d.ts +1 -1
  74. package/esm/components/DateSelector/DateSelector.js +111 -52
  75. package/esm/components/DateSelector/DateSelector.js.map +1 -1
  76. package/esm/components/Header/Header.js +1 -1
  77. package/esm/components/Header/Header.js.map +1 -1
  78. package/esm/components/LoginDrawer/LoginDrawer.css +37 -5
  79. package/esm/components/LoginDrawer/LoginDrawer.d.ts +1 -2
  80. package/esm/components/LoginDrawer/LoginDrawer.js +2 -9
  81. package/esm/components/LoginDrawer/LoginDrawer.js.map +1 -1
  82. package/esm/components/MediaWidget/MediaWidget.css +4 -0
  83. package/esm/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.js +1 -1
  84. package/esm/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.js.map +1 -1
  85. package/esm/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyButtonWithDropdown.js +1 -1
  86. package/esm/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyButtonWithDropdown.js.map +1 -1
  87. package/esm/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyMenuItem.js +3 -0
  88. package/esm/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyMenuItem.js.map +1 -1
  89. package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js +2 -2
  90. package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js.map +1 -1
  91. package/esm/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.css +16 -7
  92. package/esm/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js +6 -4
  93. package/esm/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js.map +1 -1
  94. package/esm/components/MemoriWidget/MemoriWidget.js +69 -25
  95. package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
  96. package/esm/components/UploadButton/UploadButton.js +2 -0
  97. package/esm/components/UploadButton/UploadButton.js.map +1 -1
  98. package/esm/components/UploadButton/UploadImages/UploadImages.js +2 -2
  99. package/esm/components/UploadButton/UploadImages/UploadImages.js.map +1 -1
  100. package/esm/components/ui/Drawer.css +8 -0
  101. package/esm/components/ui/Drawer.d.ts +2 -0
  102. package/esm/components/ui/Drawer.js +2 -2
  103. package/esm/components/ui/Drawer.js.map +1 -1
  104. package/esm/components/ui/Tooltip.css +49 -1
  105. package/esm/components/ui/Tooltip.d.ts +1 -1
  106. package/esm/locales/de.json +6 -1
  107. package/esm/locales/en.json +9 -1
  108. package/esm/locales/es.json +6 -1
  109. package/esm/locales/fr.json +5 -1
  110. package/esm/locales/it.json +8 -1
  111. package/esm/styles.css +3 -2
  112. package/package.json +2 -2
  113. package/src/components/AgeVerificationModal/AgeVerificationModal.css +41 -14
  114. package/src/components/AgeVerificationModal/AgeVerificationModal.tsx +3 -1
  115. package/src/components/Auth/Auth.tsx +55 -11
  116. package/src/components/Avatar/Avatar.stories.tsx +3 -0
  117. package/src/components/Avatar/AvatarView/AvatarComponent/positionControls/positionControls.css +2 -2
  118. package/src/components/Chat/Chat.stories.tsx +16 -2
  119. package/src/components/Chat/Chat.tsx +2 -1
  120. package/src/components/Chat/__snapshots__/Chat.test.tsx.snap +1030 -30
  121. package/src/components/ChatBubble/ChatBubble.css +81 -13
  122. package/src/components/ChatBubble/ChatBubble.stories.tsx +16 -2
  123. package/src/components/ChatBubble/ChatBubble.test.tsx +17 -0
  124. package/src/components/ChatBubble/ChatBubble.tsx +144 -31
  125. package/src/components/ChatBubble/__snapshots__/ChatBubble.test.tsx.snap +304 -8
  126. package/src/components/ChatHistoryDrawer/ChatHistory.css +5 -1
  127. package/src/components/ChatInputs/ChatInputs.tsx +14 -1
  128. package/src/components/DateSelector/DateSelector.css +125 -104
  129. package/src/components/DateSelector/DateSelector.stories.tsx +1 -1
  130. package/src/components/DateSelector/DateSelector.test.tsx +137 -23
  131. package/src/components/DateSelector/DateSelector.tsx +203 -177
  132. package/src/components/Header/Header.stories.tsx +5 -1
  133. package/src/components/Header/Header.tsx +1 -1
  134. package/src/components/Header/__snapshots__/Header.test.tsx.snap +1 -1
  135. package/src/components/LoginDrawer/LoginDrawer.css +37 -5
  136. package/src/components/LoginDrawer/LoginDrawer.stories.tsx +0 -1
  137. package/src/components/LoginDrawer/LoginDrawer.test.tsx +0 -1
  138. package/src/components/LoginDrawer/LoginDrawer.tsx +0 -19
  139. package/src/components/MediaWidget/MediaWidget.css +4 -0
  140. package/src/components/MemoriArtifactSystem/ArtifactDrawer.stories.tsx +996 -204
  141. package/src/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.tsx +2 -2
  142. package/src/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyButtonWithDropdown.tsx +1 -1
  143. package/src/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyMenuItem.tsx +3 -0
  144. package/src/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.tsx +56 -54
  145. package/src/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.css +16 -7
  146. package/src/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.tsx +12 -3
  147. package/src/components/MemoriWidget/MemoriWidget.stories.tsx +6 -3
  148. package/src/components/MemoriWidget/MemoriWidget.tsx +123 -48
  149. package/src/components/UploadButton/UploadButton.tsx +2 -0
  150. package/src/components/UploadButton/UploadImages/UploadImages.tsx +3 -2
  151. package/src/components/layouts/FullBody/FullBody.stories.tsx +9 -10
  152. package/src/components/layouts/Totem/Totem.stories.tsx +8 -9
  153. package/src/components/layouts/ZoomedFullBody/ZoomedFullBody.stories.tsx +8 -9
  154. package/src/components/layouts/layouts.stories.tsx +10 -9
  155. package/src/components/ui/Drawer.css +8 -0
  156. package/src/components/ui/Drawer.tsx +16 -12
  157. package/src/components/ui/Tooltip.css +49 -1
  158. package/src/components/ui/Tooltip.tsx +1 -1
  159. package/src/index.stories.tsx +18 -0
  160. package/src/locales/de.json +6 -1
  161. package/src/locales/en.json +9 -1
  162. package/src/locales/es.json +6 -1
  163. package/src/locales/fr.json +5 -1
  164. package/src/locales/it.json +8 -1
  165. package/src/mocks/data.ts +4 -2
  166. package/src/styles.css +3 -2
  167. package/src/components/SignupForm/SignupForm.test.tsx +0 -40
  168. package/src/components/SignupForm/SignupForm.tsx +0 -457
  169. package/src/components/SignupForm/__snapshots__/SignupForm.test.tsx.snap +0 -247
@@ -1,137 +1,158 @@
1
+ /* Screen reader only - visually hidden but accessible */
2
+ .sr-only {
3
+ position: absolute;
4
+ overflow: hidden;
5
+ width: 1px;
6
+ height: 1px;
7
+ padding: 0;
8
+ border-width: 0;
9
+ margin: -1px;
10
+ clip: rect(0, 0, 0, 0);
11
+ white-space: nowrap;
12
+ }
13
+
14
+ /* Base Container */
1
15
  .memori--date-selector {
2
- display: flex;
3
- flex-wrap: nowrap;
16
+ width: 100%;
17
+ /* margin-top: 1.5rem; */
4
18
  }
5
19
 
6
- .memori--date-selector__select {
7
- width: 30%;
20
+ /* Mobile Styles */
21
+ .memori--date-selector--mobile {
22
+ display: flex;
23
+ width: 100%;
8
24
  max-width: 100%;
9
- margin: 1.5rem 1.5% 0;
25
+ box-sizing: border-box;
26
+ flex-direction: column;
27
+ padding: 0;
28
+ margin: 1rem 0;
10
29
  }
11
30
 
12
- .memori--date-selector__select-button {
13
- position: relative;
31
+ .memori--date-selector__mobile-label {
32
+ display: block;
14
33
  width: 100%;
15
- padding-top: 0.5rem;
16
- padding-right: 2.5rem;
17
- padding-bottom: 0.5rem;
18
- padding-left: 0.75rem;
19
- border: 1px solid #e5e7eb;
20
- border-radius: 0.5rem;
21
- background: #fff;
22
- box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0.1) 0px 4px 6px -1px,
23
- rgba(0, 0, 0, 0.1) 0px 2px 4px -2px;
24
- cursor: pointer;
34
+ margin-bottom: 0.5rem;
35
+ color: #374151;
36
+ font-size: 0.95rem;
37
+ font-weight: 500;
25
38
  text-align: left;
26
39
  }
27
40
 
28
- .memori--date-selector__select-button:focus {
29
- border-color: #cbd5e0;
30
- box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.5);
31
- }
32
-
33
- .memori--date-selector__select-button:focus-visible {
34
- border-color: #63b3ed;
35
- box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.5);
41
+ .memori--date-selector__mobile-input {
42
+ width: 100%;
43
+ max-width: 100%;
44
+ min-height: 48px;
45
+ box-sizing: border-box;
46
+ padding: 0.875rem 1rem;
47
+ border: 1px solid #e5e7eb;
48
+ border-radius: 0.5rem;
49
+ -webkit-appearance: none;
50
+ appearance: none;
51
+ background: #ffffff;
52
+ /* Touch-friendly */
53
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
54
+ color: #1f2937;
55
+ font-size: 1rem;
56
+ transition: all 0.2s ease;
36
57
  }
37
58
 
38
- .memori--date-selector__select-button:hover {
39
- border-color: #e2e8f0;
59
+ .memori--date-selector__mobile-input:focus {
60
+ border-color: var(--memori-primary, #9333ea);
61
+ box-shadow: 0 0 0 3px rgba(147, 51, 234, 0.1);
62
+ outline: none;
40
63
  }
41
64
 
42
- .memori--date-selector__select-button:active {
43
- border-color: #e2e8f0;
65
+ .memori--date-selector__mobile-input:active {
66
+ border-color: var(--memori-primary, #9333ea);
44
67
  }
45
68
 
46
- .memori--date-selector__select-button:disabled {
47
- border-color: #e2e8f0;
48
- background-color: #f7fafc;
49
- color: #a0aec0;
69
+ .memori--date-selector__mobile-input:disabled {
70
+ background-color: #f9fafb;
71
+ color: #9ca3af;
50
72
  cursor: not-allowed;
73
+ opacity: 0.6;
51
74
  }
52
75
 
53
- @media (min-width: 640px) {
54
- .memori--date-selector__select-button {
55
- font-size: 0.875rem;
56
- line-height: 1.25rem;
57
- }
58
- }
59
-
60
- .memori--date-selector__select-label {
61
- display: inline-block;
62
- margin-bottom: 0.25rem;
76
+ /* Desktop Styles */
77
+ .memori--date-selector--desktop {
78
+ display: flex;
79
+ flex-wrap: wrap;
80
+ justify-content: center;
81
+ gap: 1rem;
63
82
  }
64
83
 
65
- .memori--date-selector__select--value {
66
- display: block;
67
- overflow: hidden;
68
- text-overflow: ellipsis;
69
- white-space: nowrap;
84
+ .memori--date-selector__input-group {
85
+ display: flex;
86
+ min-width: 80px;
87
+ /* flex: 1; */
88
+ flex-direction: column;
70
89
  }
71
90
 
72
- .memori--date-selector__select--icon {
73
- position: absolute;
74
- top: 0;
75
- right: 0;
76
- bottom: 0;
77
- display: flex;
78
- align-items: center;
79
- padding-right: 0.5rem;
80
- pointer-events: none;
91
+ .memori--date-selector__input-group--year {
92
+ min-width: 100px;
81
93
  }
82
94
 
83
- .memori--date-selector__select--icon svg {
84
- width: 1.25rem;
85
- height: 1.25rem;
86
- color: rgb(156 163 175/1);
95
+ .memori--date-selector__label {
96
+ display: inline-block;
97
+ margin-bottom: 0.5rem;
98
+ color: #4b5563;
99
+ font-size: 0.875rem;
100
+ font-weight: 500;
101
+ letter-spacing: 0.01em;
87
102
  }
88
103
 
89
- ul.memori--date-selector__select-options {
90
- position: absolute;
91
- z-index: 1;
92
- overflow: auto;
104
+ .memori--date-selector__input {
93
105
  width: 100%;
94
- max-width: min(18rem, 30%);
95
- max-height: 15rem;
96
- padding-top: 0.25rem;
97
- padding-right: 0;
98
- padding-bottom: 0.25rem;
99
- padding-left: 0;
100
- border-radius: 0.375rem;
101
- margin-top: 0.25rem;
102
- margin-right: 0;
103
- margin-bottom: 0;
104
- margin-left: 0;
105
- background: #fff;
106
- box-shadow: rgb(255, 255, 255) 0px 0px 0px 0px, rgba(0, 0, 0, 0.05) 0px 0px 0px 1px,
107
- rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.1) 0px 4px 6px -4px;
108
- list-style: none;
109
- }
110
-
111
- @media (min-width: 640px) {
112
- .memori--date-selector__select-options {
113
- font-size: 0.875rem;
114
- line-height: 1.25rem;
115
- }
106
+ padding: 0.75rem 1rem;
107
+ border: 2px solid #e5e7eb;
108
+ border-radius: 0.75rem;
109
+ -moz-appearance: textfield;
110
+ appearance: textfield;
111
+ /* Remove spinner buttons */
112
+ background: #ffffff;
113
+ color: #1f2937;
114
+ font-size: 0.95rem;
115
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
116
+ }
117
+
118
+ .memori--date-selector__input::-webkit-outer-spin-button,
119
+ .memori--date-selector__input::-webkit-inner-spin-button {
120
+ margin: 0;
121
+ -webkit-appearance: none;
122
+ }
123
+
124
+ .memori--date-selector__input:focus {
125
+ border-color: var(--memori-primary);
126
+ box-shadow: 0 0 0 4px rgba(var(--memori-primary-rgb), 0.1);
127
+ outline: none;
128
+ transform: translateY(-1px);
129
+ }
130
+
131
+ .memori--date-selector__input:disabled {
132
+ border-color: #e5e7eb;
133
+ background: #f9fafb;
134
+ color: #9ca3af;
135
+ cursor: not-allowed;
136
+ opacity: 0.6;
116
137
  }
117
138
 
118
- li.memori--date-selector__select-option {
119
- position: relative;
120
- padding-top: 0.5rem;
121
- padding-right: 1rem;
122
- padding-bottom: 0.5rem;
123
- padding-left: 1rem;
124
- color: rgb(17 24 39/1);
125
- cursor: pointer;
126
- user-select: none;
139
+ .memori--date-selector__input::placeholder {
140
+ color: #9ca3af;
127
141
  }
128
142
 
129
- li.memori--date-selector__select-option:hover,
130
- li.memori--date-selector__select-option:focus {
131
- background-color: #f7fafc;
132
- }
143
+ /* Responsive adjustments */
144
+ @media (max-width: 767px) {
145
+ .memori--date-selector--desktop {
146
+ display: none;
147
+ /* Hide desktop version on mobile if both are rendered for some reason */
148
+ }
133
149
 
134
- li.memori--date-selector__select-option:focus {
135
- outline: 2px solid #63b3ed;
136
- outline-offset: 2px;
137
- }
150
+ .memori--date-selector--mobile {
151
+ margin: 0.75rem 0;
152
+ }
153
+
154
+ .memori--date-selector__mobile-input {
155
+ min-height: 44px;
156
+ font-size: 16px; /* Prevents zoom on iOS */
157
+ }
158
+ }
@@ -34,5 +34,5 @@ export const Disabled = Template.bind({});
34
34
  Disabled.args = {
35
35
  defaultDate: new Date(Date.now()),
36
36
  onChange: () => {},
37
- disabled: false,
37
+ disabled: true,
38
38
  };
@@ -1,6 +1,5 @@
1
- import { render } from '@testing-library/react';
1
+ import { render, screen, fireEvent, waitFor } from '@testing-library/react';
2
2
  import DateSelector from './DateSelector';
3
- import { DateTime } from 'luxon';
4
3
 
5
4
  const dateMock = new Date(Date.UTC(2022, 8, 24, 0, 0, 0, 0));
6
5
 
@@ -9,27 +8,142 @@ Date.now = jest.fn(() => dateMock.valueOf());
9
8
 
10
9
  jest.spyOn(Date, 'now').mockImplementation(() => dateMock.valueOf());
11
10
 
12
- it('renders DateSelector unchanged', () => {
13
- const { container } = render(
14
- <DateSelector defaultDate={new Date(Date.now())} onChange={jest.fn()} />
15
- );
16
- expect(container).toMatchSnapshot();
17
- });
11
+ describe('DateSelector', () => {
12
+ const mockOnChange = jest.fn();
18
13
 
19
- it('renders DateSelector with default value unchanged', () => {
20
- const { container } = render(
21
- <DateSelector defaultDate="2023-12-14T08:48:06.977Z" onChange={jest.fn()} />
22
- );
23
- expect(container).toMatchSnapshot();
24
- });
14
+ beforeEach(() => {
15
+ mockOnChange.mockClear();
16
+ });
17
+
18
+ it('renders DateSelector with empty inputs when no defaultDate provided', () => {
19
+ render(<DateSelector onChange={mockOnChange} />);
20
+
21
+ const dayInput = screen.getByLabelText(/day/i);
22
+ const monthInput = screen.getByLabelText(/month/i);
23
+ const yearInput = screen.getByLabelText(/year/i);
24
+
25
+ expect(dayInput).toHaveValue(null); // number input value is null/empty string
26
+ expect(monthInput).toHaveValue(null);
27
+ expect(yearInput).toHaveValue(null);
28
+
29
+ // Should call onChange with undefined initially or not at all if we want strict behavior
30
+ // Based on implementation: useEffect triggers on mount. If empty, calls onChange(undefined).
31
+ expect(mockOnChange).toHaveBeenCalledWith(undefined);
32
+ });
33
+
34
+ it('renders DateSelector with default value correctly', () => {
35
+ const defaultDate = new Date(Date.now());
36
+ render(
37
+ <DateSelector defaultDate={defaultDate} onChange={mockOnChange} />
38
+ );
39
+
40
+ const dayInput = screen.getByLabelText(/day/i);
41
+ const monthInput = screen.getByLabelText(/month/i);
42
+ const yearInput = screen.getByLabelText(/year/i);
43
+
44
+ expect(dayInput).toHaveValue(defaultDate.getDate());
45
+ expect(monthInput).toHaveValue(defaultDate.getMonth() + 1);
46
+ expect(yearInput).toHaveValue(defaultDate.getFullYear());
47
+ });
48
+
49
+ describe('Desktop View', () => {
50
+ it('updates day and calls onChange with undefined if incomplete', () => {
51
+ render(<DateSelector onChange={mockOnChange} />);
52
+ const dayInput = screen.getByLabelText(/day/i);
53
+
54
+ fireEvent.change(dayInput, { target: { value: '15' } });
55
+
56
+ expect(dayInput).toHaveValue(15);
57
+ expect(mockOnChange).toHaveBeenCalledWith(undefined);
58
+ });
59
+
60
+ it('calls onChange with valid date when all fields are filled', () => {
61
+ render(<DateSelector onChange={mockOnChange} />);
62
+ const dayInput = screen.getByLabelText(/day/i);
63
+ const monthInput = screen.getByLabelText(/month/i);
64
+ const yearInput = screen.getByLabelText(/year/i);
65
+
66
+ fireEvent.change(dayInput, { target: { value: '15' } });
67
+ fireEvent.change(monthInput, { target: { value: '5' } });
68
+ fireEvent.change(yearInput, { target: { value: '1990' } });
69
+
70
+ expect(mockOnChange).toHaveBeenCalledWith(
71
+ expect.objectContaining({
72
+ year: 1990,
73
+ month: 5,
74
+ day: 15,
75
+ })
76
+ );
77
+ });
78
+
79
+ it('auto-focuses month after day is filled', () => {
80
+ render(<DateSelector onChange={mockOnChange} />);
81
+ const dayInput = screen.getByLabelText(/day/i);
82
+ const monthInput = screen.getByLabelText(/month/i);
83
+
84
+ fireEvent.change(dayInput, { target: { value: '12' } });
85
+
86
+ expect(monthInput).toHaveFocus();
87
+ });
88
+
89
+ it('auto-focuses year after month is filled', () => {
90
+ render(<DateSelector onChange={mockOnChange} />);
91
+ const monthInput = screen.getByLabelText(/month/i);
92
+ const yearInput = screen.getByLabelText(/year/i);
93
+
94
+ fireEvent.change(monthInput, { target: { value: '12' } });
95
+
96
+ expect(yearInput).toHaveFocus();
97
+ });
98
+
99
+ it('disables all inputs when disabled prop is true', () => {
100
+ render(<DateSelector disabled onChange={mockOnChange} />);
101
+
102
+ const dayInput = screen.getByLabelText(/day/i);
103
+ const monthInput = screen.getByLabelText(/month/i);
104
+ const yearInput = screen.getByLabelText(/year/i);
105
+
106
+ expect(dayInput).toBeDisabled();
107
+ expect(monthInput).toBeDisabled();
108
+ expect(yearInput).toBeDisabled();
109
+ });
110
+ });
111
+
112
+ describe('Mobile View', () => {
113
+ it('renders native date input on mobile', () => {
114
+ render(<DateSelector onChange={mockOnChange} />);
115
+
116
+ const dateInput = screen.getByLabelText(/date/i);
117
+ expect(dateInput).toBeInTheDocument();
118
+ expect(dateInput).toHaveAttribute('type', 'date');
119
+ });
120
+
121
+ it('calls onChange when mobile date input changes', async () => {
122
+ render(<DateSelector onChange={mockOnChange} />);
123
+
124
+ const dateInput = screen.getByLabelText(/date/i);
125
+ fireEvent.change(dateInput, { target: { value: '1995-06-15' } });
126
+
127
+ await waitFor(() => {
128
+ expect(mockOnChange).toHaveBeenCalledWith(
129
+ expect.objectContaining({
130
+ year: 1995,
131
+ month: 6,
132
+ day: 15
133
+ })
134
+ );
135
+ });
136
+ });
137
+
138
+ it('calls onChange with undefined when mobile input is cleared', async () => {
139
+ render(<DateSelector defaultDate="1995-06-15" onChange={mockOnChange} />);
140
+
141
+ const dateInput = screen.getByLabelText(/date/i);
142
+ fireEvent.change(dateInput, { target: { value: '' } });
25
143
 
26
- it('renders DateSelector disabled unchanged', () => {
27
- const { container } = render(
28
- <DateSelector
29
- disabled
30
- defaultDate={new Date(Date.now())}
31
- onChange={jest.fn()}
32
- />
33
- );
34
- expect(container).toMatchSnapshot();
144
+ await waitFor(() => {
145
+ expect(mockOnChange).toHaveBeenCalledWith(undefined);
146
+ });
147
+ });
148
+ });
35
149
  });