profile-pane 3.2.1 → 3.2.2-test.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 (241) hide show
  1. package/README.md +50 -0
  2. package/lib/303.profile-pane.js +1362 -0
  3. package/lib/303.profile-pane.js.map +1 -0
  4. package/lib/303.profile-pane.min.js +2 -0
  5. package/lib/303.profile-pane.min.js.map +1 -0
  6. package/lib/ProfileView.css +1090 -0
  7. package/lib/ProfileView.d.ts +2 -1
  8. package/lib/ProfileView.d.ts.map +1 -1
  9. package/lib/ProfileView.js +64 -36
  10. package/lib/buttonsHelper.d.ts +1 -1
  11. package/lib/buttonsHelper.d.ts.map +1 -1
  12. package/lib/buttonsHelper.js +2 -1
  13. package/lib/editProfilePane/EditCVCard.js +1 -1
  14. package/lib/editProfilePane/EditCommunitiesCard.js +1 -1
  15. package/lib/editProfilePane/EditFriendsCard.js +1 -1
  16. package/lib/editProfilePane/EditProfileView.d.ts +1 -1
  17. package/lib/editProfilePane/EditProfileView.d.ts.map +1 -1
  18. package/lib/editProfilePane/EditProfileView.js +4 -5
  19. package/lib/editProfilePane/editProfilePresenter.d.ts.map +1 -1
  20. package/lib/editProfilePane/editProfilePresenter.js +5 -4
  21. package/lib/icons-svg/profileIcons.d.ts +1 -1
  22. package/lib/icons-svg/profileIcons.d.ts.map +1 -1
  23. package/lib/icons-svg/profileIcons.js +9 -17
  24. package/lib/index.d.ts +1 -8
  25. package/lib/index.d.ts.map +1 -1
  26. package/lib/index.js +74 -40
  27. package/lib/ontology/otherPreferencesForm.ttl +32 -0
  28. package/lib/ontology/resumeForm.ttl +349 -0
  29. package/lib/ontology/socialMedia.ttl +433 -0
  30. package/lib/profile-pane.js +32266 -13247
  31. package/lib/profile-pane.js.map +1 -1
  32. package/lib/profile-pane.min.js +2315 -935
  33. package/lib/profile-pane.min.js.map +1 -1
  34. package/lib/rdfFormsHelper.d.ts +13 -1
  35. package/lib/rdfFormsHelper.d.ts.map +1 -1
  36. package/lib/rdfFormsHelper.js +13 -1
  37. package/lib/sections/bio/BioEditDialog.d.ts.map +1 -1
  38. package/lib/sections/bio/BioEditDialog.js +7 -7
  39. package/lib/sections/bio/BioSection.css +300 -0
  40. package/lib/sections/bio/BioSection.d.ts +3 -2
  41. package/lib/sections/bio/BioSection.d.ts.map +1 -1
  42. package/lib/sections/bio/BioSection.js +26 -19
  43. package/lib/sections/bio/mutations.d.ts.map +1 -1
  44. package/lib/sections/bio/mutations.js +14 -3
  45. package/lib/sections/contactInfo/ContactInfoEditDialog.css +354 -0
  46. package/lib/sections/contactInfo/ContactInfoEditDialog.d.ts +3 -1
  47. package/lib/sections/contactInfo/ContactInfoEditDialog.d.ts.map +1 -1
  48. package/lib/sections/contactInfo/ContactInfoEditDialog.js +183 -98
  49. package/lib/sections/contactInfo/ContactInfoSection.css +125 -0
  50. package/lib/sections/contactInfo/ContactInfoSection.d.ts +2 -0
  51. package/lib/sections/contactInfo/ContactInfoSection.d.ts.map +1 -1
  52. package/lib/sections/contactInfo/ContactInfoSection.js +64 -41
  53. package/lib/sections/contactInfo/mutations.d.ts.map +1 -1
  54. package/lib/sections/contactInfo/mutations.js +51 -16
  55. package/lib/sections/education/EducationEditDialog.d.ts +3 -1
  56. package/lib/sections/education/EducationEditDialog.d.ts.map +1 -1
  57. package/lib/sections/education/EducationEditDialog.js +170 -92
  58. package/lib/sections/education/EducationSection.css +133 -0
  59. package/lib/sections/education/EducationSection.d.ts +3 -2
  60. package/lib/sections/education/EducationSection.d.ts.map +1 -1
  61. package/lib/sections/education/EducationSection.js +32 -25
  62. package/lib/sections/education/mutations.d.ts.map +1 -1
  63. package/lib/sections/education/mutations.js +14 -3
  64. package/lib/sections/heading/HeadingEditDialog.d.ts +4 -1
  65. package/lib/sections/heading/HeadingEditDialog.d.ts.map +1 -1
  66. package/lib/sections/heading/HeadingEditDialog.js +287 -162
  67. package/lib/sections/heading/HeadingSection.css +862 -0
  68. package/lib/sections/heading/HeadingSection.d.ts +3 -2
  69. package/lib/sections/heading/HeadingSection.d.ts.map +1 -1
  70. package/lib/sections/heading/HeadingSection.js +63 -32
  71. package/lib/sections/heading/imageHelpers.d.ts +1 -0
  72. package/lib/sections/heading/imageHelpers.d.ts.map +1 -1
  73. package/lib/sections/heading/imageHelpers.js +40 -1
  74. package/lib/sections/heading/mutations.d.ts.map +1 -1
  75. package/lib/sections/heading/mutations.js +86 -23
  76. package/lib/sections/heading/selectors.d.ts.map +1 -1
  77. package/lib/sections/heading/selectors.js +14 -3
  78. package/lib/sections/heading/types.d.ts +1 -2
  79. package/lib/sections/heading/types.d.ts.map +1 -1
  80. package/lib/sections/languages/LanguageEditDialog.d.ts +3 -1
  81. package/lib/sections/languages/LanguageEditDialog.d.ts.map +1 -1
  82. package/lib/sections/languages/LanguageEditDialog.js +202 -119
  83. package/lib/sections/languages/LanguageSection.css +53 -0
  84. package/lib/sections/languages/LanguageSection.d.ts +2 -0
  85. package/lib/sections/languages/LanguageSection.d.ts.map +1 -1
  86. package/lib/sections/languages/LanguageSection.js +42 -31
  87. package/lib/sections/languages/mutations.d.ts.map +1 -1
  88. package/lib/sections/languages/mutations.js +60 -161
  89. package/lib/sections/languages/selectors.d.ts.map +1 -1
  90. package/lib/sections/languages/selectors.js +1 -2
  91. package/lib/sections/projects/ProjectEditDialog.d.ts +2 -1
  92. package/lib/sections/projects/ProjectEditDialog.d.ts.map +1 -1
  93. package/lib/sections/projects/ProjectEditDialog.js +13 -24
  94. package/lib/sections/projects/ProjectSection.css +368 -0
  95. package/lib/sections/projects/ProjectSection.d.ts +2 -1
  96. package/lib/sections/projects/ProjectSection.d.ts.map +1 -1
  97. package/lib/sections/projects/ProjectSection.js +116 -34
  98. package/lib/sections/projects/mutations.d.ts.map +1 -1
  99. package/lib/sections/projects/mutations.js +109 -132
  100. package/lib/sections/projects/selectors.d.ts.map +1 -1
  101. package/lib/sections/projects/selectors.js +4 -45
  102. package/lib/{QRCodeCard.d.ts → sections/qrcode/QRCodeCard.d.ts} +2 -1
  103. package/lib/sections/qrcode/QRCodeCard.d.ts.map +1 -0
  104. package/lib/{QRCodeCard.js → sections/qrcode/QRCodeCard.js} +59 -11
  105. package/lib/sections/qrcode/QRCodeSection.css +108 -0
  106. package/lib/sections/qrcode/QRCodeSection.d.ts +4 -0
  107. package/lib/sections/qrcode/QRCodeSection.d.ts.map +1 -0
  108. package/lib/sections/qrcode/QRCodeSection.js +17 -0
  109. package/lib/sections/resume/ResumeEditDialog.d.ts +10 -1
  110. package/lib/sections/resume/ResumeEditDialog.d.ts.map +1 -1
  111. package/lib/sections/resume/ResumeEditDialog.js +531 -149
  112. package/lib/sections/resume/ResumeSection.css +350 -0
  113. package/lib/sections/resume/ResumeSection.d.ts +3 -2
  114. package/lib/sections/resume/ResumeSection.d.ts.map +1 -1
  115. package/lib/sections/resume/ResumeSection.js +78 -49
  116. package/lib/sections/resume/mutations.d.ts.map +1 -1
  117. package/lib/sections/resume/mutations.js +17 -3
  118. package/lib/sections/resume/selectors.d.ts.map +1 -1
  119. package/lib/sections/resume/selectors.js +1 -0
  120. package/lib/sections/resume/types.d.ts +1 -0
  121. package/lib/sections/resume/types.d.ts.map +1 -1
  122. package/lib/sections/shared/collapsibleSection.d.ts.map +1 -1
  123. package/lib/sections/shared/collapsibleSection.js +1 -0
  124. package/lib/sections/shared/phoneCountries.d.ts +1 -1
  125. package/lib/sections/shared/phoneCountries.d.ts.map +1 -1
  126. package/lib/sections/shared/phoneCountries.js +2 -2
  127. package/lib/sections/shared/projectCommunityNodes.d.ts +6 -0
  128. package/lib/sections/shared/projectCommunityNodes.d.ts.map +1 -0
  129. package/lib/sections/shared/projectCommunityNodes.js +56 -0
  130. package/lib/sections/shared/rdfMutationHelpers.d.ts +35 -2
  131. package/lib/sections/shared/rdfMutationHelpers.d.ts.map +1 -1
  132. package/lib/sections/shared/rdfMutationHelpers.js +290 -14
  133. package/lib/sections/shared/sectionCardHelpers.d.ts.map +1 -1
  134. package/lib/sections/shared/sectionCardHelpers.js +80 -11
  135. package/lib/sections/shared/types.d.ts +24 -0
  136. package/lib/sections/shared/types.d.ts.map +1 -1
  137. package/lib/sections/skills/SkillsEditDialog.d.ts +3 -1
  138. package/lib/sections/skills/SkillsEditDialog.d.ts.map +1 -1
  139. package/lib/sections/skills/SkillsEditDialog.js +136 -115
  140. package/lib/sections/skills/SkillsSection.css +173 -0
  141. package/lib/sections/skills/SkillsSection.d.ts +2 -0
  142. package/lib/sections/skills/SkillsSection.d.ts.map +1 -1
  143. package/lib/sections/skills/SkillsSection.js +107 -47
  144. package/lib/sections/skills/mutations.d.ts.map +1 -1
  145. package/lib/sections/skills/mutations.js +25 -21
  146. package/lib/sections/skills/selectors.d.ts.map +1 -1
  147. package/lib/sections/skills/selectors.js +5 -3
  148. package/lib/sections/social/SocialEditDialog.d.ts +3 -1
  149. package/lib/sections/social/SocialEditDialog.d.ts.map +1 -1
  150. package/lib/sections/social/SocialEditDialog.js +170 -62
  151. package/lib/sections/social/SocialSection.css +194 -0
  152. package/lib/sections/social/SocialSection.d.ts +4 -3
  153. package/lib/sections/social/SocialSection.d.ts.map +1 -1
  154. package/lib/sections/social/SocialSection.js +59 -43
  155. package/lib/sections/social/mutations.d.ts.map +1 -1
  156. package/lib/sections/social/mutations.js +23 -132
  157. package/lib/specialButtons/AddMeToYourFriends.css +54 -0
  158. package/lib/specialButtons/addContact/AddMeToYourContacts.css +1118 -0
  159. package/lib/specialButtons/addContact/ContactCreationDialog.d.ts +10 -0
  160. package/lib/specialButtons/addContact/ContactCreationDialog.d.ts.map +1 -0
  161. package/lib/specialButtons/addContact/ContactCreationDialog.js +1123 -0
  162. package/lib/specialButtons/addContact/addMeToYourContacts.d.ts +16 -0
  163. package/lib/specialButtons/addContact/addMeToYourContacts.d.ts.map +1 -0
  164. package/lib/specialButtons/addContact/addMeToYourContacts.js +136 -0
  165. package/lib/specialButtons/addContact/contactsErrors.d.ts +8 -0
  166. package/lib/specialButtons/addContact/contactsErrors.d.ts.map +1 -0
  167. package/lib/specialButtons/addContact/contactsErrors.js +106 -0
  168. package/lib/specialButtons/addContact/contactsTypes.d.ts +43 -0
  169. package/lib/specialButtons/addContact/contactsTypes.d.ts.map +1 -0
  170. package/lib/specialButtons/addContact/contactsTypes.js +5 -0
  171. package/lib/specialButtons/addContact/helpers.d.ts +7 -0
  172. package/lib/specialButtons/addContact/helpers.d.ts.map +1 -0
  173. package/lib/specialButtons/addContact/helpers.js +103 -0
  174. package/lib/specialButtons/addContact/mutations.d.ts +16 -0
  175. package/lib/specialButtons/addContact/mutations.d.ts.map +1 -0
  176. package/lib/specialButtons/addContact/mutations.js +300 -0
  177. package/lib/specialButtons/addContact/selectors.d.ts +10 -0
  178. package/lib/specialButtons/addContact/selectors.d.ts.map +1 -0
  179. package/lib/specialButtons/addContact/selectors.js +163 -0
  180. package/lib/{addMeToYourFriends.d.ts → specialButtons/addMeToYourFriends.d.ts} +6 -4
  181. package/lib/specialButtons/addMeToYourFriends.d.ts.map +1 -0
  182. package/lib/{addMeToYourFriends.js → specialButtons/addMeToYourFriends.js} +46 -11
  183. package/lib/styles/CollapsibleSection.css +519 -0
  184. package/lib/styles/EditDialogs.css +506 -686
  185. package/lib/styles/EditDialogs.responsive.css +989 -0
  186. package/lib/texts/buttonTexts.d.ts +9 -0
  187. package/lib/texts/buttonTexts.d.ts.map +1 -0
  188. package/lib/texts/buttonTexts.js +14 -0
  189. package/lib/texts/dialogTexts.d.ts +14 -0
  190. package/lib/texts/dialogTexts.d.ts.map +1 -0
  191. package/lib/texts/dialogTexts.js +19 -0
  192. package/lib/texts/messageTexts.d.ts +42 -0
  193. package/lib/texts/messageTexts.d.ts.map +1 -0
  194. package/lib/texts/messageTexts.js +47 -0
  195. package/lib/texts/profileTexts.d.ts +14 -0
  196. package/lib/texts/profileTexts.d.ts.map +1 -0
  197. package/lib/texts/profileTexts.js +19 -0
  198. package/lib/texts/qrCodeTexts.d.ts +2 -0
  199. package/lib/texts/qrCodeTexts.d.ts.map +1 -0
  200. package/lib/texts/qrCodeTexts.js +7 -0
  201. package/lib/texts.d.ts +5 -60
  202. package/lib/texts.d.ts.map +1 -1
  203. package/lib/texts.js +55 -70
  204. package/lib/ui/dialog.css +233 -0
  205. package/lib/ui/dialog.d.ts +15 -1
  206. package/lib/ui/dialog.d.ts.map +1 -1
  207. package/lib/ui/dialog.js +245 -45
  208. package/lib/ui/dialog.responsive.css +195 -0
  209. package/lib/ui/errors.d.ts.map +1 -1
  210. package/lib/ui/errors.js +2 -1
  211. package/lib/ui/spinner.d.ts +3 -0
  212. package/lib/ui/spinner.d.ts.map +1 -0
  213. package/lib/ui/spinner.js +13 -0
  214. package/lib/utils/debug.d.ts +5 -0
  215. package/lib/utils/debug.d.ts.map +1 -0
  216. package/lib/utils/debug.js +23 -0
  217. package/lib/utils/errorDisplay.d.ts +2 -0
  218. package/lib/utils/errorDisplay.d.ts.map +1 -0
  219. package/lib/utils/errorDisplay.js +19 -0
  220. package/package.json +32 -25
  221. package/lib/ChatWithMe.d.ts +0 -7
  222. package/lib/ChatWithMe.d.ts.map +0 -1
  223. package/lib/ChatWithMe.js +0 -90
  224. package/lib/QRCodeCard.d.ts.map +0 -1
  225. package/lib/addMeToYourFriends.d.ts.map +0 -1
  226. package/lib/sections/heading/camera.d.ts +0 -19
  227. package/lib/sections/heading/camera.d.ts.map +0 -1
  228. package/lib/sections/heading/camera.js +0 -199
  229. package/lib/styles/BioSection.css +0 -77
  230. package/lib/styles/CVCard.css +0 -142
  231. package/lib/styles/ChatWithMe.css +0 -6
  232. package/lib/styles/ContactInfoEditDialog.css +0 -153
  233. package/lib/styles/EducationCard.css +0 -103
  234. package/lib/styles/HeadingSection.css +0 -309
  235. package/lib/styles/ProfileCard.css +0 -66
  236. package/lib/styles/ProfileView.css +0 -65
  237. package/lib/styles/ProjectsCard.css +0 -206
  238. package/lib/styles/QRCodeCard.css +0 -43
  239. package/lib/styles/SocialCard.css +0 -89
  240. package/lib/styles/dialog.css +0 -209
  241. package/lib/styles/utilities.css +0 -740
@@ -4,19 +4,327 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.createResumeEditDialog = createResumeEditDialog;
7
+ exports.fetchWikidataOrganizationSuggestions = fetchWikidataOrganizationSuggestions;
7
8
  var _dialog = require("../../ui/dialog");
8
9
  var _litHtml = require("lit-html");
10
+ require("solid-ui/components/actions/button");
11
+ require("solid-ui/components/forms/combobox");
12
+ require("solid-ui/components/forms/select");
9
13
  require("../../styles/EditDialogs.css");
10
- require("../../styles/ContactInfoEditDialog.css");
14
+ require("../contactInfo/ContactInfoEditDialog.css");
11
15
  var _rdflib = require("rdflib");
12
16
  var _mutations = require("./mutations");
13
17
  var _rowState = require("../shared/rowState");
14
18
  var _textUtils = require("../../textUtils");
15
19
  var _profileIcons = require("../../icons-svg/profileIcons");
16
20
  var _texts = require("../../texts");
21
+ const RESUME_ORGANIZATION_TYPE_OPTIONS = [{
22
+ label: 'Corporation',
23
+ value: 'Corporation'
24
+ }, {
25
+ label: 'Educational Organization',
26
+ value: 'EducationalOrganization'
27
+ }, {
28
+ label: 'Research Organization',
29
+ value: 'ResearchOrganization'
30
+ }, {
31
+ label: 'Government Organization',
32
+ value: 'GovernmentOrganization'
33
+ }, {
34
+ label: 'NGO',
35
+ value: 'NGO'
36
+ }, {
37
+ label: 'Performing Group',
38
+ value: 'PerformingGroup'
39
+ }, {
40
+ label: 'Project',
41
+ value: 'Project'
42
+ }, {
43
+ label: 'Sports Organization',
44
+ value: 'SportsOrganization'
45
+ }, {
46
+ label: 'Other',
47
+ value: 'Other'
48
+ }];
49
+ const RESUME_MONTH_OPTIONS = [{
50
+ value: '01',
51
+ label: 'January'
52
+ }, {
53
+ value: '02',
54
+ label: 'February'
55
+ }, {
56
+ value: '03',
57
+ label: 'March'
58
+ }, {
59
+ value: '04',
60
+ label: 'April'
61
+ }, {
62
+ value: '05',
63
+ label: 'May'
64
+ }, {
65
+ value: '06',
66
+ label: 'June'
67
+ }, {
68
+ value: '07',
69
+ label: 'July'
70
+ }, {
71
+ value: '08',
72
+ label: 'August'
73
+ }, {
74
+ value: '09',
75
+ label: 'September'
76
+ }, {
77
+ value: '10',
78
+ label: 'October'
79
+ }, {
80
+ value: '11',
81
+ label: 'November'
82
+ }, {
83
+ value: '12',
84
+ label: 'December'
85
+ }];
86
+ const WIKIDATA_ORGANIZATION_SEARCH_URI = 'https://www.wikidata.org/w/api.php?action=wbsearchentities&language=$(language)&type=item&limit=$(limit)&format=json&origin=*&search=$(name)';
87
+ const WIKIDATA_ENTITY_LOOKUP_URI = 'https://www.wikidata.org/w/api.php?action=wbgetentities&format=json&origin=*&props=claims&ids=$(ids)';
88
+ const WIKIDATA_ORGANIZATION_SEARCH_LANGUAGE = 'en';
89
+ const WIKIDATA_ORGANIZATION_SEARCH_LIMIT = 8;
90
+ const WIKIDATA_ORGANIZATION_SEARCH_CANDIDATE_LIMIT = 24;
91
+ const RESUME_ORGANIZATION_TYPE_WIKIDATA_CLASS_URIS = {
92
+ Corporation: ['http://www.wikidata.org/entity/Q6881511', 'http://www.wikidata.org/entity/Q4830453'],
93
+ EducationalOrganization: ['http://www.wikidata.org/entity/Q178706', 'http://www.wikidata.org/entity/Q2385804', 'http://www.wikidata.org/entity/Q1664720'],
94
+ ResearchOrganization: ['http://www.wikidata.org/entity/Q31855'],
95
+ GovernmentOrganization: ['http://www.wikidata.org/entity/Q327333'],
96
+ NGO: ['http://www.wikidata.org/entity/Q163740', 'http://www.wikidata.org/entity/Q79913', 'http://www.wikidata.org/entity/Q708676'],
97
+ PerformingGroup: ['http://www.wikidata.org/entity/Q32178211'],
98
+ Project: ['http://www.wikidata.org/entity/Q170584'],
99
+ SportsOrganization: ['http://www.wikidata.org/entity/Q4438121'],
100
+ Other: ['http://www.wikidata.org/entity/Q43229']
101
+ };
102
+ const RESUME_ORGANIZATION_SEARCH_CLASS_URIS = Array.from(new Set(RESUME_ORGANIZATION_TYPE_OPTIONS.flatMap(option => RESUME_ORGANIZATION_TYPE_WIKIDATA_CLASS_URIS[option.value] || [])));
103
+ const RESUME_PRESENT_MONTH_VALUE = '__present__';
17
104
  function sanitizeResumeFieldValue(value) {
18
105
  return (0, _textUtils.sanitizeTextValue)(value);
19
106
  }
107
+ function normalizeResumeOrganizationPublicId(value) {
108
+ return sanitizeResumeFieldValue(value);
109
+ }
110
+ function buildWikidataOrganizationSearchUrl(name) {
111
+ return WIKIDATA_ORGANIZATION_SEARCH_URI.replace('$(language)', encodeURIComponent(WIKIDATA_ORGANIZATION_SEARCH_LANGUAGE)).replace('$(limit)', encodeURIComponent(String(WIKIDATA_ORGANIZATION_SEARCH_CANDIDATE_LIMIT))).replace('$(name)', encodeURIComponent(name));
112
+ }
113
+ function buildWikidataEntityLookupUrl(ids) {
114
+ return WIKIDATA_ENTITY_LOOKUP_URI.replace('$(ids)', encodeURIComponent(ids.join('|')));
115
+ }
116
+ function getWikidataIdFromUri(value) {
117
+ const trimmed = sanitizeResumeFieldValue(value);
118
+ const match = trimmed.match(/Q\d+/);
119
+ return match ? match[0] : '';
120
+ }
121
+ function getWikidataClaimIds(entity, property) {
122
+ const claims = entity?.claims?.[property] || [];
123
+ return claims.map(claim => claim?.mainsnak).filter(snak => snak?.snaktype === 'value').map(snak => snak?.datavalue?.value?.id).filter(id => typeof id === 'string' && id.length > 0);
124
+ }
125
+ function getAllowedOrganizationTypeIds(selectedType) {
126
+ const normalizedType = normalizeResumeOrganizationTypeValue(selectedType);
127
+ const typeUris = RESUME_ORGANIZATION_TYPE_WIKIDATA_CLASS_URIS[normalizedType];
128
+ if (!typeUris?.length) {
129
+ return RESUME_ORGANIZATION_SEARCH_CLASS_URIS.map(uri => getWikidataIdFromUri(uri)).filter(Boolean);
130
+ }
131
+ return typeUris.map(uri => getWikidataIdFromUri(uri)).filter(Boolean);
132
+ }
133
+ const allowedOrganizationTypeIdSetCache = new Map();
134
+ function getAllowedOrganizationTypeIdSet(selectedType) {
135
+ const normalizedType = normalizeResumeOrganizationTypeValue(selectedType);
136
+ const cachedIds = allowedOrganizationTypeIdSetCache.get(normalizedType);
137
+ if (cachedIds) {
138
+ return cachedIds;
139
+ }
140
+ const allowedIds = new Set(getAllowedOrganizationTypeIds(normalizedType));
141
+ allowedOrganizationTypeIdSetCache.set(normalizedType, allowedIds);
142
+ return allowedIds;
143
+ }
144
+ async function fetchWikidataEntities(ids) {
145
+ const uniqueIds = Array.from(new Set(ids.filter(Boolean)));
146
+ if (!uniqueIds.length || typeof fetch !== 'function') return {};
147
+ const response = await fetch(buildWikidataEntityLookupUrl(uniqueIds));
148
+ if (!response.ok) return {};
149
+ const payload = await response.json();
150
+ return payload?.entities || {};
151
+ }
152
+ function entityMatchesAllowedOrganizationTypes(entityId, entityMap, selectedType) {
153
+ const allowedIds = getAllowedOrganizationTypeIdSet(selectedType);
154
+ const visited = new Set();
155
+ const agenda = [entityId];
156
+ while (agenda.length) {
157
+ const currentId = agenda.shift();
158
+ if (!currentId || visited.has(currentId)) continue;
159
+ visited.add(currentId);
160
+ if (allowedIds.has(currentId)) {
161
+ return true;
162
+ }
163
+ const entity = entityMap[currentId];
164
+ agenda.push(...getWikidataClaimIds(entity, 'P31'));
165
+ agenda.push(...getWikidataClaimIds(entity, 'P279'));
166
+ }
167
+ return false;
168
+ }
169
+ function toResumeOrganizationLabel(result) {
170
+ return result?.label || result?.match?.text || result?.id || '';
171
+ }
172
+ function toResumeOrganizationSuggestion(result) {
173
+ const label = sanitizeResumeFieldValue(toResumeOrganizationLabel(result));
174
+ const publicId = normalizeResumeOrganizationPublicId(typeof result?.concepturi === 'string' ? result.concepturi : typeof result?.url === 'string' ? result.url : '');
175
+ return {
176
+ label,
177
+ publicId
178
+ };
179
+ }
180
+ function dedupeResumeOrganizationSuggestions(suggestions) {
181
+ const seen = new Set();
182
+ return suggestions.filter(suggestion => {
183
+ if (!suggestion.label || !suggestion.publicId) return false;
184
+ const key = suggestion.label.toLowerCase();
185
+ if (seen.has(key)) return false;
186
+ seen.add(key);
187
+ return true;
188
+ });
189
+ }
190
+ async function fetchWikidataOrganizationSuggestions(name, selectedType) {
191
+ const query = sanitizeResumeFieldValue(name);
192
+ if (query.length < 2 || typeof fetch !== 'function') return [];
193
+ try {
194
+ const response = await fetch(buildWikidataOrganizationSearchUrl(query));
195
+ if (!response.ok) return [];
196
+ const payload = await response.json();
197
+ const results = Array.isArray(payload?.search) ? payload.search : [];
198
+ const suggestions = dedupeResumeOrganizationSuggestions(results.map(result => toResumeOrganizationSuggestion(result)));
199
+ const resultIds = suggestions.map(suggestion => getWikidataIdFromUri(suggestion.publicId)).filter(Boolean);
200
+ if (!resultIds.length) {
201
+ return suggestions.slice(0, WIKIDATA_ORGANIZATION_SEARCH_LIMIT);
202
+ }
203
+ const resultEntities = await fetchWikidataEntities(resultIds);
204
+ const relatedIds = Array.from(new Set(Object.values(resultEntities).flatMap(entity => [...getWikidataClaimIds(entity, 'P31'), ...getWikidataClaimIds(entity, 'P279')])));
205
+ const relatedEntities = await fetchWikidataEntities(relatedIds);
206
+ const entityMap = {
207
+ ...resultEntities,
208
+ ...relatedEntities
209
+ };
210
+ if (Object.keys(entityMap).length === 0) {
211
+ return suggestions.slice(0, WIKIDATA_ORGANIZATION_SEARCH_LIMIT);
212
+ }
213
+ const filteredSuggestions = suggestions.filter(suggestion => {
214
+ const entityId = getWikidataIdFromUri(suggestion.publicId);
215
+ return entityMatchesAllowedOrganizationTypes(entityId, entityMap, selectedType);
216
+ });
217
+ return filteredSuggestions.slice(0, WIKIDATA_ORGANIZATION_SEARCH_LIMIT);
218
+ } catch {
219
+ return [];
220
+ }
221
+ }
222
+ function toResumeOrganizationComboboxOption(suggestion) {
223
+ return {
224
+ label: suggestion.label,
225
+ value: suggestion.publicId,
226
+ publicId: suggestion.publicId
227
+ };
228
+ }
229
+ function readResumeOrganizationComboboxInputValue(event) {
230
+ const customEvent = event;
231
+ if (typeof customEvent.detail?.value === 'string') {
232
+ return customEvent.detail.value;
233
+ }
234
+ const target = event.target;
235
+ return typeof target?.value === 'string' ? target.value : '';
236
+ }
237
+ function readResumeOrganizationComboboxChange(event) {
238
+ const customEvent = event;
239
+ if (customEvent.detail?.option) {
240
+ return customEvent.detail.option;
241
+ }
242
+ return null;
243
+ }
244
+ function createResumeOrganizationSuggestionProvider(getSelectedType) {
245
+ return async query => {
246
+ const suggestions = await fetchWikidataOrganizationSuggestions(query, getSelectedType());
247
+ return suggestions.map(toResumeOrganizationComboboxOption);
248
+ };
249
+ }
250
+ function normalizeResumeOrganizationTypeValue(value) {
251
+ return RESUME_ORGANIZATION_TYPE_OPTIONS.some(option => option.value === value) ? value : RESUME_ORGANIZATION_TYPE_OPTIONS[0]?.value || '';
252
+ }
253
+ function readResumeOrganizationTypeChange(event) {
254
+ const customEvent = event;
255
+ if (typeof customEvent.detail?.value === 'string') {
256
+ return customEvent.detail.value;
257
+ }
258
+ const target = event.target;
259
+ return typeof target?.value === 'string' ? target.value : '';
260
+ }
261
+ function readResumeSelectChange(event) {
262
+ return readResumeOrganizationTypeChange(event);
263
+ }
264
+ function getResumeYearOptions(selectedYears) {
265
+ const currentYear = new Date().getFullYear();
266
+ const baseYearOptions = Array.from({
267
+ length: 120
268
+ }, (_, i) => String(currentYear - i));
269
+ const yearOptions = Array.from(new Set([...baseYearOptions, ...selectedYears].filter(Boolean))).sort((a, b) => Number(b) - Number(a));
270
+ return yearOptions.map(year => ({
271
+ label: year,
272
+ value: year
273
+ }));
274
+ }
275
+ function getResumeDateSelectOptions(kind, selectedYears, isCurrentRole) {
276
+ if (kind === 'start-month') {
277
+ return RESUME_MONTH_OPTIONS;
278
+ }
279
+ if (kind === 'start-year') {
280
+ return getResumeYearOptions(selectedYears);
281
+ }
282
+ if (kind === 'end-month') {
283
+ if (isCurrentRole) {
284
+ return [{
285
+ value: RESUME_PRESENT_MONTH_VALUE,
286
+ label: 'Present'
287
+ }];
288
+ }
289
+ return RESUME_MONTH_OPTIONS;
290
+ }
291
+ if (kind === 'end-year' && isCurrentRole) {
292
+ return [{
293
+ value: '',
294
+ label: ''
295
+ }];
296
+ }
297
+ return getResumeYearOptions(selectedYears);
298
+ }
299
+ function getResumeDateSelectLabel(kind, row) {
300
+ switch (kind) {
301
+ case 'start-month':
302
+ case 'end-month':
303
+ return row?.isCurrentRole && kind === 'end-month' ? 'Present' : 'Select Month';
304
+ case 'start-year':
305
+ return 'Select Year';
306
+ case 'end-year':
307
+ return row?.isCurrentRole ? '' : 'Select Year';
308
+ default:
309
+ return '';
310
+ }
311
+ }
312
+ function getResumeDateSelectValue(kind, row) {
313
+ const startDateParts = parseYearMonthFromDateText((0, _textUtils.toText)(row?.startDate));
314
+ const endDateParts = parseYearMonthFromDateText((0, _textUtils.toText)(row?.endDate));
315
+ switch (kind) {
316
+ case 'start-month':
317
+ return startDateParts.month;
318
+ case 'start-year':
319
+ return startDateParts.year;
320
+ case 'end-month':
321
+ return row?.isCurrentRole ? RESUME_PRESENT_MONTH_VALUE : endDateParts.month;
322
+ case 'end-year':
323
+ return row?.isCurrentRole ? '' : endDateParts.year;
324
+ default:
325
+ return '';
326
+ }
327
+ }
20
328
  function parseYearMonthFromDateText(dateText) {
21
329
  const normalized = (dateText || '').trim();
22
330
  if (!normalized) return {
@@ -47,7 +355,8 @@ function toFormState(resumeData) {
47
355
  endDate: role.endDate,
48
356
  isCurrentRole: role.isCurrentRole ?? !role.endDate,
49
357
  orgName: sanitizeResumeFieldValue((0, _textUtils.toText)(role.orgName)),
50
- orgType: sanitizeResumeFieldValue((0, _textUtils.toText)(role.orgType)),
358
+ orgPublicId: normalizeResumeOrganizationPublicId(sanitizeResumeFieldValue((0, _textUtils.toText)(role.orgPublicId))),
359
+ orgType: normalizeResumeOrganizationTypeValue(sanitizeResumeFieldValue((0, _textUtils.toText)(role.orgType))),
51
360
  orgLocation: sanitizeResumeFieldValue((0, _textUtils.toText)(role.orgLocation)),
52
361
  orgHomePage: sanitizeResumeFieldValue((0, _textUtils.toText)(role.orgHomePage)),
53
362
  description: sanitizeResumeFieldValue((0, _textUtils.toText)(role.description)),
@@ -62,7 +371,8 @@ function toFormState(resumeData) {
62
371
  endDate: undefined,
63
372
  isCurrentRole: false,
64
373
  orgName: '',
65
- orgType: '',
374
+ orgPublicId: '',
375
+ orgType: RESUME_ORGANIZATION_TYPE_OPTIONS[0].value,
66
376
  orgLocation: '',
67
377
  orgHomePage: '',
68
378
  description: '',
@@ -88,6 +398,66 @@ function validateResumeBeforeSave(rows) {
88
398
  ok: true
89
399
  };
90
400
  }
401
+ function initializeResumeOrganizationTypeSelects(form, resumeData) {
402
+ const selectElements = form.querySelectorAll('solid-ui-select[data-resume-organization-type-index]');
403
+ selectElements.forEach(selectElement => {
404
+ const rowIndex = Number(selectElement.dataset.resumeOrganizationTypeIndex);
405
+ if (Number.isNaN(rowIndex)) return;
406
+ const resumeRow = resumeData[rowIndex];
407
+ if (!resumeRow) return;
408
+ selectElement.options = RESUME_ORGANIZATION_TYPE_OPTIONS;
409
+ selectElement.value = normalizeResumeOrganizationTypeValue(resumeRow.orgType || '');
410
+ selectElement.label = '';
411
+ });
412
+ }
413
+ function initializeResumeOrganizationComboboxes(form, resumeData) {
414
+ const comboboxElements = form.querySelectorAll('solid-ui-combobox[data-resume-organization-index]');
415
+ comboboxElements.forEach(comboboxElement => {
416
+ const rowIndex = Number(comboboxElement.dataset.resumeOrganizationIndex);
417
+ if (Number.isNaN(rowIndex)) return;
418
+ const resumeRow = resumeData[rowIndex];
419
+ if (!resumeRow) return;
420
+ const options = resumeRow.orgPublicId && resumeRow.orgName ? [{
421
+ label: resumeRow.orgName,
422
+ value: resumeRow.orgPublicId,
423
+ publicId: resumeRow.orgPublicId
424
+ }] : [];
425
+ comboboxElement.suggestionProvider = createResumeOrganizationSuggestionProvider(() => normalizeResumeOrganizationTypeValue(resumeRow.orgType || ''));
426
+ comboboxElement.options = options;
427
+ comboboxElement.value = resumeRow.orgPublicId || '';
428
+ comboboxElement.inputValue = resumeRow.orgName || '';
429
+ comboboxElement.label = '';
430
+ comboboxElement.placeholder = 'Company or Organization';
431
+ });
432
+ }
433
+ function syncResumeOrganizationRowsFromComboboxes(form, resumeData) {
434
+ const comboboxElements = form.querySelectorAll('solid-ui-combobox[data-resume-organization-index]');
435
+ comboboxElements.forEach(comboboxElement => {
436
+ const rowIndex = Number(comboboxElement.dataset.resumeOrganizationIndex);
437
+ if (Number.isNaN(rowIndex) || !resumeData[rowIndex]) return;
438
+ const comboboxInput = comboboxElement.shadowRoot?.querySelector('input');
439
+ const nextName = sanitizeResumeFieldValue(comboboxInput?.value || comboboxElement.inputValue || '');
440
+ const nextPublicId = normalizeResumeOrganizationPublicId(comboboxElement.value || '');
441
+ (0, _rowState.applyRowFieldChange)(resumeData[rowIndex], 'orgName', nextName, rowHasContent);
442
+ resumeData[rowIndex].orgPublicId = nextPublicId;
443
+ });
444
+ }
445
+ function initializeResumeDateSelects(form, resumeData) {
446
+ const selectElements = form.querySelectorAll('solid-ui-select[data-resume-date-kind]');
447
+ selectElements.forEach(selectElement => {
448
+ const kind = selectElement.dataset.resumeDateKind;
449
+ const rowIndex = Number(selectElement.dataset.resumeRowIndex);
450
+ if (!kind || Number.isNaN(rowIndex)) return;
451
+ const resumeRow = resumeData[rowIndex];
452
+ if (!resumeRow) return;
453
+ const startDateParts = parseYearMonthFromDateText((0, _textUtils.toText)(resumeRow.startDate));
454
+ const endDateParts = parseYearMonthFromDateText((0, _textUtils.toText)(resumeRow.endDate));
455
+ const selectedYears = [startDateParts.year, endDateParts.year];
456
+ selectElement.options = getResumeDateSelectOptions(kind, selectedYears, Boolean(resumeRow.isCurrentRole));
457
+ selectElement.value = getResumeDateSelectValue(kind, resumeRow);
458
+ selectElement.label = getResumeDateSelectLabel(kind, resumeRow);
459
+ });
460
+ }
91
461
  function renderResumeInputRow({
92
462
  resumeData,
93
463
  index,
@@ -130,59 +500,7 @@ function renderResumeInputRow({
130
500
  const endYearParsedText = endDateParts.year;
131
501
  const isCurrentRoleId = `resume-current-role-${index}`;
132
502
  const currentYear = new Date().getFullYear();
133
- const baseYearOptions = Array.from({
134
- length: 120
135
- }, (_, i) => String(currentYear - i));
136
- const yearOptions = Array.from(new Set([...baseYearOptions, startYearText, endYearParsedText].filter(Boolean))).sort((a, b) => Number(b) - Number(a));
137
- const monthOptions = [{
138
- value: '01',
139
- label: 'January'
140
- }, {
141
- value: '02',
142
- label: 'February'
143
- }, {
144
- value: '03',
145
- label: 'March'
146
- }, {
147
- value: '04',
148
- label: 'April'
149
- }, {
150
- value: '05',
151
- label: 'May'
152
- }, {
153
- value: '06',
154
- label: 'June'
155
- }, {
156
- value: '07',
157
- label: 'July'
158
- }, {
159
- value: '08',
160
- label: 'August'
161
- }, {
162
- value: '09',
163
- label: 'September'
164
- }, {
165
- value: '10',
166
- label: 'October'
167
- }, {
168
- value: '11',
169
- label: 'November'
170
- }, {
171
- value: '12',
172
- label: 'December'
173
- }];
174
- const renderMonthOptions = (selectedMonth, emptyLabel = 'Select Month') => (0, _litHtml.html)`
175
- <option value="" ?selected=${!selectedMonth}>${emptyLabel}</option>
176
- ${monthOptions.map(month => (0, _litHtml.html)`
177
- <option value=${month.value} ?selected=${month.value === selectedMonth}>${month.label}</option>
178
- `)}
179
- `;
180
- const renderYearOptions = (selectedYear, emptyLabel = 'Select Year') => (0, _litHtml.html)`
181
- <option value="" ?selected=${!selectedYear}>${emptyLabel}</option>
182
- ${yearOptions.map(year => (0, _litHtml.html)`
183
- <option value=${year} ?selected=${year === selectedYear}>${year}</option>
184
- `)}
185
- `;
503
+ const selectedYears = [startYearText, endYearParsedText];
186
504
  const handleResumeInput = field => e => {
187
505
  const target = e.target;
188
506
  const nextValue = sanitizeResumeFieldValue(target.value);
@@ -203,8 +521,7 @@ function renderResumeInputRow({
203
521
  /* The following function was generated by AI Model: GPT-5.3-Codex */
204
522
  /* Prompt: can you make this a month drop down for the start year */
205
523
  const handleStartMonthChange = event => {
206
- const target = event.target;
207
- const month = target.value;
524
+ const month = readResumeSelectChange(event);
208
525
  const year = parseYearMonthFromDateText((0, _textUtils.toText)(resumeData[index]?.startDate)).year || String(currentYear);
209
526
  const nextStartDate = buildDateLiteral(month, year);
210
527
  if (resumeData[index]) {
@@ -213,8 +530,7 @@ function renderResumeInputRow({
213
530
  }
214
531
  };
215
532
  const handleStartYearChange = event => {
216
- const target = event.target;
217
- const year = target.value;
533
+ const year = readResumeSelectChange(event);
218
534
  const month = parseYearMonthFromDateText((0, _textUtils.toText)(resumeData[index]?.startDate)).month || '01';
219
535
  const nextStartDate = buildDateLiteral(month, year);
220
536
  if (resumeData[index]) {
@@ -223,8 +539,8 @@ function renderResumeInputRow({
223
539
  }
224
540
  };
225
541
  const handleEndMonthChange = event => {
226
- const target = event.target;
227
- const month = target.value;
542
+ if (resumeData[index]?.isCurrentRole) return;
543
+ const month = readResumeSelectChange(event);
228
544
  const year = parseYearMonthFromDateText((0, _textUtils.toText)(resumeData[index]?.endDate)).year || String(currentYear);
229
545
  const nextEndDate = buildDateLiteral(month, year);
230
546
  if (resumeData[index]) {
@@ -233,8 +549,8 @@ function renderResumeInputRow({
233
549
  }
234
550
  };
235
551
  const handleEndYearChange = event => {
236
- const target = event.target;
237
- const year = target.value;
552
+ if (resumeData[index]?.isCurrentRole) return;
553
+ const year = readResumeSelectChange(event);
238
554
  const month = parseYearMonthFromDateText((0, _textUtils.toText)(resumeData[index]?.endDate)).month || '01';
239
555
  const nextEndDate = buildDateLiteral(month, year);
240
556
  if (resumeData[index]) {
@@ -257,48 +573,45 @@ function renderResumeInputRow({
257
573
  if (target.checked) {
258
574
  (0, _rowState.applyRowFieldChange)(resumeData[index], 'endDate', undefined, rowHasContent);
259
575
  }
260
- const formRoot = target.form || target.closest('form');
261
- const endMonthSelect = formRoot?.querySelector(`#${endMonthSelectId}`);
262
- const endYearSelect = formRoot?.querySelector(`#${endYearSelectId}`);
263
- if (endMonthSelect) {
264
- endMonthSelect.disabled = target.checked;
265
- endMonthSelect.value = '';
266
- const emptyOption = endMonthSelect.options[0];
267
- if (emptyOption) {
268
- emptyOption.text = target.checked ? 'Present' : 'Select Month';
269
- }
270
- }
271
- if (endYearSelect) {
272
- endYearSelect.disabled = target.checked;
273
- endYearSelect.value = '';
274
- const emptyOption = endYearSelect.options[0];
275
- if (emptyOption) {
276
- emptyOption.text = target.checked ? '' : 'Select Year';
277
- }
278
- }
576
+ onChange();
279
577
  }
280
578
  };
281
579
  const handleOrganizationTypeInput = e => {
282
- const target = e.target;
283
- const nextType = target.value;
580
+ const nextType = normalizeResumeOrganizationTypeValue(readResumeOrganizationTypeChange(e));
284
581
  if (resumeRow) {
285
582
  (0, _rowState.applyRowSelectChange)(resumeRow, 'orgType', nextType);
583
+ resumeRow.orgPublicId = '';
286
584
  onChange();
287
585
  }
288
586
  };
587
+ const handleOrganizationNameInput = e => {
588
+ const nextValue = sanitizeResumeFieldValue(readResumeOrganizationComboboxInputValue(e));
589
+ if (resumeRow) {
590
+ (0, _rowState.applyRowFieldChange)(resumeRow, 'orgName', nextValue, rowHasContent);
591
+ resumeRow.orgPublicId = '';
592
+ }
593
+ };
594
+ const handleOrganizationNameChange = e => {
595
+ const selectedOption = readResumeOrganizationComboboxChange(e);
596
+ if (!resumeRow || !selectedOption?.publicId) return;
597
+ (0, _rowState.applyRowFieldChange)(resumeRow, 'orgName', sanitizeResumeFieldValue(selectedOption.label), rowHasContent);
598
+ resumeRow.orgPublicId = selectedOption.publicId;
599
+ };
289
600
  return (0, _litHtml.html)`
290
601
  <div class="profile-edit-dialog__row profile-edit-dialog__row--resume-entry-header" role="group" aria-labelledby=${experienceHeadingId}>
291
602
  <h3 id=${experienceHeadingId} class="profile-edit-dialog__entry-heading">${label}</h3>
292
603
  <div class="profile-edit-dialog__actions profile-edit-dialog__actions--edge">
293
- <button
604
+ <solid-ui-button
294
605
  type="button"
606
+ variant="icon"
607
+ size="md"
295
608
  class="profile-edit-dialog__delete-button"
296
609
  aria-label=${`Delete resume ${displayIndex + 1}`}
297
610
  title=${_texts.deleteEntryButtonTitleText}
298
611
  @click=${handleDelete}
299
612
  >
300
- <span class="profile-edit-dialog__delete-icon" aria-hidden="true">${_profileIcons.trashIcon}</span>
301
- </button>
613
+ <span slot="icon" class="profile-edit-dialog__delete-icon" aria-hidden="true">${_profileIcons.trashIcon}</span>
614
+ </solid-ui-button>
302
615
  </div>
303
616
  </div>
304
617
  <label aria-label=${`${label} Title`} class="label profile-edit-dialog__field">
@@ -318,36 +631,28 @@ function renderResumeInputRow({
318
631
  />
319
632
  </label>
320
633
  <div class="profile-edit-dialog__row">
634
+ <label aria-label=${`${label} Organization Type`} class="label profile-edit-dialog__field">
635
+ Organization Type
636
+ <solid-ui-select
637
+ class="profile-edit-dialog__resume-organization-type-select"
638
+ name=${organizationTypeName}
639
+ id=${organizationTypeSelectId}
640
+ data-resume-organization-type-index=${String(index)}
641
+ .options=${RESUME_ORGANIZATION_TYPE_OPTIONS}
642
+ .value=${normalizeResumeOrganizationTypeValue(resumeRow?.orgType || '')}
643
+ .label=${''}
644
+ @change=${handleOrganizationTypeInput}
645
+ ></solid-ui-select>
646
+ </label>
321
647
  <label aria-label=${`${label} Organization Name`} class="label profile-edit-dialog__field">
322
648
  Company or Organization
323
- <input
324
- class="input"
325
- type="text"
649
+ <solid-ui-combobox
326
650
  name=${organizationName}
327
- .value=${resumeRow?.orgName || ''}
651
+ data-resume-organization-index=${String(index)}
328
652
  required
329
- data-contact-field="organizationName"
330
- data-entry-node=${resumeRow?.entryNode || ''}
331
- data-row-status=${resumeRow?.status || 'n/a'}
332
- placeholder="Company or Organization"
333
- autocomplete="organization"
334
- inputmode="text"
335
- @change=${handleResumeInput('orgName')}
336
- />
337
- </label>
338
- <label aria-label=${`${label} Organization Type`} class="label profile-edit-dialog__field">
339
- Organization Type
340
- <select name=${organizationTypeName} id=${organizationTypeSelectId} @change=${handleOrganizationTypeInput} .value=${resumeRow?.orgType || ''}>
341
- <option value="Corporation">Corporation</option>
342
- <option value="EducationalOrganization">Educational Organization</option>
343
- <option value="ResearchOrganization">Research Organization</option>
344
- <option value="GovernmentOrganization">Government Organization</option>
345
- <option value="NGO">NGO</option>
346
- <option value="PerformingGroup">Performing Group</option>
347
- <option value="Project">Project</option>
348
- <option value="SportsOrganization">Sports Organization</option>
349
- <option value="Other">Other</option>
350
- </select>
653
+ @input=${handleOrganizationNameInput}
654
+ @change=${handleOrganizationNameChange}
655
+ ></solid-ui-combobox>
351
656
  </label>
352
657
  </div>
353
658
  <div class="profile-edit-dialog__row">
@@ -388,35 +693,63 @@ function renderResumeInputRow({
388
693
  <label aria-label=${`Start Date ${displayIndex + 1}`} class="label profile-edit-dialog__field profile-edit-dialog__field--date-group">
389
694
  <span>Start Date</span>
390
695
  <div class="profile-edit-dialog__date-pair">
391
- <select name=${startMonthInputName} id=${startMonthSelectId} aria-label=${startMonthLabel} @change=${handleStartMonthChange}>
392
- ${renderMonthOptions(startMonthValue)}
393
- </select>
394
- <select name=${startYearInputName} id=${startYearSelectId} aria-label=${startYearLabel} @change=${handleStartYearChange}>
395
- ${renderYearOptions(startYearText)}
396
- </select>
696
+ <solid-ui-select
697
+ class="profile-edit-dialog__resume-date-select"
698
+ name=${startMonthInputName}
699
+ id=${startMonthSelectId}
700
+ aria-label=${startMonthLabel}
701
+ data-resume-date-kind="start-month"
702
+ data-resume-row-index=${String(index)}
703
+ .options=${getResumeDateSelectOptions('start-month', selectedYears, Boolean(resumeRow?.isCurrentRole))}
704
+ .value=${startMonthValue}
705
+ .label=${getResumeDateSelectLabel('start-month', resumeRow)}
706
+ @change=${handleStartMonthChange}
707
+ ></solid-ui-select>
708
+ <solid-ui-select
709
+ class="profile-edit-dialog__resume-date-select"
710
+ name=${startYearInputName}
711
+ id=${startYearSelectId}
712
+ aria-label=${startYearLabel}
713
+ data-resume-date-kind="start-year"
714
+ data-resume-row-index=${String(index)}
715
+ .options=${getResumeDateSelectOptions('start-year', selectedYears, Boolean(resumeRow?.isCurrentRole))}
716
+ .value=${startYearText}
717
+ .label=${getResumeDateSelectLabel('start-year', resumeRow)}
718
+ @change=${handleStartYearChange}
719
+ ></solid-ui-select>
397
720
  </div>
398
721
  </label>
399
722
  <label aria-label=${`End Date ${displayIndex + 1}`} class="label profile-edit-dialog__field profile-edit-dialog__field--date-group">
400
723
  <span>End Date</span>
401
724
  <div class="profile-edit-dialog__date-pair">
402
- <select
725
+ <solid-ui-select
726
+ class=${`profile-edit-dialog__resume-date-select${resumeRow?.isCurrentRole ? ' profile-edit-dialog__resume-date-select--disabled' : ''}`}
403
727
  name=${endMonthInputName}
404
728
  id=${endMonthSelectId}
405
729
  aria-label=${endMonthLabel}
730
+ aria-disabled=${String(Boolean(resumeRow?.isCurrentRole))}
731
+ tabindex=${resumeRow?.isCurrentRole ? '-1' : '0'}
732
+ data-resume-date-kind="end-month"
733
+ data-resume-row-index=${String(index)}
734
+ .options=${getResumeDateSelectOptions('end-month', selectedYears, Boolean(resumeRow?.isCurrentRole))}
735
+ .value=${resumeRow?.isCurrentRole ? RESUME_PRESENT_MONTH_VALUE : endMonthValue}
736
+ .label=${getResumeDateSelectLabel('end-month', resumeRow)}
406
737
  @change=${handleEndMonthChange}
407
- ?disabled=${Boolean(resumeRow?.isCurrentRole)}
408
- >
409
- ${renderMonthOptions(endMonthValue, resumeRow?.isCurrentRole ? 'Present' : 'Select Month')}
410
- </select>
411
- <select
738
+ ></solid-ui-select>
739
+ <solid-ui-select
740
+ class=${`profile-edit-dialog__resume-date-select${resumeRow?.isCurrentRole ? ' profile-edit-dialog__resume-date-select--disabled' : ''}`}
412
741
  name=${endYearInputName}
413
742
  id=${endYearSelectId}
414
743
  aria-label=${endYearLabel}
744
+ aria-disabled=${String(Boolean(resumeRow?.isCurrentRole))}
745
+ tabindex=${resumeRow?.isCurrentRole ? '-1' : '0'}
746
+ data-resume-date-kind="end-year"
747
+ data-resume-row-index=${String(index)}
748
+ .options=${getResumeDateSelectOptions('end-year', selectedYears, Boolean(resumeRow?.isCurrentRole))}
749
+ .value=${resumeRow?.isCurrentRole ? '' : endYearParsedText}
750
+ .label=${getResumeDateSelectLabel('end-year', resumeRow)}
415
751
  @change=${handleEndYearChange}
416
- ?disabled=${Boolean(resumeRow?.isCurrentRole)}
417
- >
418
- ${renderYearOptions(endYearParsedText, resumeRow?.isCurrentRole ? '' : 'Select Year')}
419
- </select>
752
+ ></solid-ui-select>
420
753
  </div>
421
754
  </label>
422
755
  </div>
@@ -486,16 +819,24 @@ function renderResumeEditTemplate(form, formState, rerender, viewerMode) {
486
819
  ${renderResumeSection(formState.resumeData, rerender)}
487
820
  ${viewerMode !== 'owner' ? (0, _litHtml.html)`<p class="profile-edit-dialog__login-message">${_texts.ownerLoginRequiredDialogMessageText}</p>` : null}
488
821
  `, form);
822
+ initializeResumeOrganizationTypeSelects(form, formState.resumeData);
823
+ initializeResumeOrganizationComboboxes(form, formState.resumeData);
824
+ initializeResumeDateSelects(form, formState.resumeData);
489
825
  }
490
826
  function captureResumeDialogRenderState(form) {
491
827
  const dialog = form.closest('dialog');
492
828
  const description = dialog?.querySelector('#modal-desc');
493
829
  const activeElement = form.ownerDocument.activeElement;
830
+ const activeTextField = activeElement instanceof HTMLInputElement || activeElement instanceof HTMLTextAreaElement ? activeElement : null;
494
831
  return {
495
832
  dialogScrollTop: dialog?.scrollTop || 0,
496
833
  descriptionScrollTop: description?.scrollTop || 0,
497
834
  activeId: activeElement?.id || '',
498
- activeName: activeElement?.getAttribute('name') || ''
835
+ activeName: activeElement?.getAttribute('name') || '',
836
+ selectionStart: activeTextField?.selectionStart ?? null,
837
+ selectionEnd: activeTextField?.selectionEnd ?? null,
838
+ fieldScrollLeft: activeTextField?.scrollLeft || 0,
839
+ fieldScrollTop: activeTextField?.scrollTop || 0
499
840
  };
500
841
  }
501
842
  function restoreResumeDialogRenderState(form, state) {
@@ -512,22 +853,61 @@ function restoreResumeDialogRenderState(form, state) {
512
853
  if (!nextActive && escapedName) {
513
854
  nextActive = form.querySelector(`[name="${escapedName}"]`);
514
855
  }
515
- if (nextActive && typeof nextActive.focus === 'function') {
516
- nextActive.focus({
517
- preventScroll: true
518
- });
856
+ focusResumeFieldElement(nextActive, {
857
+ selectionStart: state.selectionStart,
858
+ selectionEnd: state.selectionEnd,
859
+ scrollLeft: state.fieldScrollLeft,
860
+ scrollTop: state.fieldScrollTop
861
+ });
862
+ }
863
+ function getResumeFocusableTarget(element) {
864
+ if (!element) return null;
865
+ if (element.tagName === 'SOLID-UI-COMBOBOX') {
866
+ const comboboxInput = element.shadowRoot?.querySelector('input');
867
+ if (comboboxInput) return comboboxInput;
519
868
  }
869
+ return element;
520
870
  }
521
- function focusResumeField(form, selector) {
522
- const nextField = form.querySelector(selector);
523
- if (!nextField || typeof nextField.focus !== 'function') return;
524
- nextField.focus({
871
+ function focusResumeFieldElement(element, options = {}) {
872
+ const focusTarget = getResumeFocusableTarget(element);
873
+ if (!focusTarget || typeof focusTarget.focus !== 'function') return;
874
+ const view = focusTarget.ownerDocument.defaultView;
875
+ const shouldAvoidFocus = Boolean(view?.matchMedia && (view.matchMedia('(pointer: coarse)').matches || view.matchMedia('(max-width: 640px)').matches));
876
+ if (shouldAvoidFocus) {
877
+ focusTarget.scrollIntoView({
878
+ block: 'nearest',
879
+ behavior: 'auto'
880
+ });
881
+ return;
882
+ }
883
+ focusTarget.focus({
525
884
  preventScroll: true
526
885
  });
527
- if (nextField instanceof HTMLInputElement || nextField instanceof HTMLTextAreaElement) {
528
- nextField.select();
886
+ if (focusTarget instanceof HTMLInputElement || focusTarget instanceof HTMLTextAreaElement) {
887
+ const selectionStart = options.selectionStart ?? focusTarget.value.length;
888
+ const selectionEnd = options.selectionEnd ?? selectionStart;
889
+ focusTarget.setSelectionRange(selectionStart, selectionEnd);
890
+ focusTarget.scrollLeft = options.scrollLeft ?? focusTarget.scrollLeft;
891
+ focusTarget.scrollTop = options.scrollTop ?? focusTarget.scrollTop;
892
+ requestAnimationFrame(() => {
893
+ focusTarget.scrollLeft = options.scrollLeft ?? focusTarget.scrollLeft;
894
+ focusTarget.scrollTop = options.scrollTop ?? focusTarget.scrollTop;
895
+ });
896
+ }
897
+ if (element?.tagName === 'SOLID-UI-COMBOBOX') {
898
+ const comboboxHost = element;
899
+ if (comboboxHost._closePopup) {
900
+ requestAnimationFrame(() => {
901
+ comboboxHost._closePopup?.();
902
+ });
903
+ }
529
904
  }
530
905
  }
906
+ function focusResumeField(form, selector) {
907
+ const nextField = form.querySelector(selector);
908
+ if (!nextField) return;
909
+ focusResumeFieldElement(nextField);
910
+ }
531
911
  function createResumeEditForm(resumeData, viewerMode) {
532
912
  const form = document.createElement('form');
533
913
  form.classList.add('profile__edit-form');
@@ -556,7 +936,8 @@ function createResumeEditForm(resumeData, viewerMode) {
556
936
  endDate: undefined,
557
937
  isCurrentRole: false,
558
938
  orgName: '',
559
- orgType: '',
939
+ orgPublicId: '',
940
+ orgType: RESUME_ORGANIZATION_TYPE_OPTIONS[0].value,
560
941
  orgLocation: '',
561
942
  orgHomePage: '',
562
943
  description: '',
@@ -587,6 +968,11 @@ async function createResumeEditDialog(event, store, subject, resumeData, viewerM
587
968
  title: _texts.editResumeDialogTitleText,
588
969
  dom,
589
970
  form,
971
+ shouldCloseWithoutSave: () => {
972
+ syncResumeOrganizationRowsFromComboboxes(form, formState.resumeData);
973
+ const plan = (0, _rowState.summarizeRowOps)(formState.resumeData, rowHasContent);
974
+ return plan.create.length === 0 && plan.update.length === 0 && plan.remove.length === 0;
975
+ },
590
976
  headerAction: {
591
977
  type: 'button',
592
978
  label: '+ Add More',
@@ -596,14 +982,10 @@ async function createResumeEditDialog(event, store, subject, resumeData, viewerM
596
982
  submitLabel: _texts.dialogSubmitLabelText,
597
983
  cancelLabel: _texts.dialogCancelLabelText,
598
984
  validate: async () => {
985
+ syncResumeOrganizationRowsFromComboboxes(form, formState.resumeData);
599
986
  if (viewerMode !== 'owner') {
600
987
  return _texts.ownerLoginRequiredDialogMessageText;
601
988
  }
602
- const plan = (0, _rowState.summarizeRowOps)(formState.resumeData, rowHasContent);
603
- const hasChanges = plan.create.length > 0 || plan.update.length > 0 || plan.remove.length > 0;
604
- if (!hasChanges) {
605
- return 'No resume changes detected.';
606
- }
607
989
  const validation = validateResumeBeforeSave(formState.resumeData);
608
990
  if (!validation.ok) {
609
991
  return validation.message || 'Please complete the required resume fields.';
@@ -611,13 +993,13 @@ async function createResumeEditDialog(event, store, subject, resumeData, viewerM
611
993
  return null;
612
994
  },
613
995
  onSave: async () => {
996
+ syncResumeOrganizationRowsFromComboboxes(form, formState.resumeData);
614
997
  const plan = (0, _rowState.summarizeRowOps)(formState.resumeData, rowHasContent);
615
998
  await (0, _mutations.processResumeMutations)(store, subject, plan);
616
999
  rerender();
617
1000
  },
618
1001
  formatSaveError: error => {
619
- const message = error instanceof Error ? error.message : String(error);
620
- return `${_texts.saveResumeUpdatesFailedPrefixText} ${message}`;
1002
+ return error instanceof Error ? error.message : _texts.saveResumeUpdatesFailedMessageText;
621
1003
  }
622
1004
  });
623
1005
  if (!result) return;