@pega/custom-dx-components 26.1.11 → 26.1.12-alpha.0.2

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 (323) hide show
  1. package/README.md +6 -2
  2. package/package.json +48 -64
  3. package/src/ai/README.md +44 -0
  4. package/src/ai/catalog/README.md +133 -0
  5. package/src/ai/catalog/best-practices/README.md +24 -0
  6. package/src/ai/catalog/best-practices/accessibility-for-async-components.md +53 -0
  7. package/src/ai/catalog/best-practices/error-handling-and-resiliency.md +116 -0
  8. package/src/ai/catalog/best-practices/genai-assistant-integration-patterns.md +49 -0
  9. package/src/ai/catalog/best-practices/performance-and-efficiency.md +109 -0
  10. package/src/ai/catalog/best-practices/security-considerations.md +93 -0
  11. package/src/ai/catalog/best-practices/testing-pconnect-components.md +245 -0
  12. package/src/ai/catalog/best-practices/troubleshooting-common-pitfalls.md +132 -0
  13. package/src/ai/catalog/pconnect-assignment-lifecycle/SKILL.md +44 -0
  14. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/README.md +39 -0
  15. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/approval-workflow-decision.md +47 -0
  16. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/attachment-upload.md +45 -0
  17. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/bulk-action-submit.md +50 -0
  18. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/confirm-before-destructive-action.md +43 -0
  19. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/create-and-stage-new-case.md +45 -0
  20. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/graceful-submit-failure.md +39 -0
  21. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/modal-assignment-submit.md +58 -0
  22. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/multi-step-wizard.md +44 -0
  23. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/resolve-or-ignore-duplicate.md +47 -0
  24. package/src/ai/catalog/pconnect-assignment-lifecycle/cookbooks/safe-case-deletion.md +36 -0
  25. package/src/ai/catalog/pconnect-case-collaboration/SKILL.md +42 -0
  26. package/src/ai/catalog/pconnect-case-collaboration/cookbooks/README.md +36 -0
  27. package/src/ai/catalog/pconnect-case-collaboration/cookbooks/look-up-user-details.md +43 -0
  28. package/src/ai/catalog/pconnect-case-collaboration/cookbooks/manage-case-attachments.md +51 -0
  29. package/src/ai/catalog/pconnect-case-collaboration/cookbooks/manage-case-participants.md +52 -0
  30. package/src/ai/catalog/pconnect-case-collaboration/cookbooks/participant-and-follower.md +40 -0
  31. package/src/ai/catalog/pconnect-case-collaboration/cookbooks/post-and-manage-feed.md +50 -0
  32. package/src/ai/catalog/pconnect-case-collaboration/cookbooks/relate-cases.md +35 -0
  33. package/src/ai/catalog/pconnect-case-collaboration/cookbooks/tag-case-and-find-related.md +44 -0
  34. package/src/ai/catalog/pconnect-data-subscriptions/SKILL.md +42 -0
  35. package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/README.md +35 -0
  36. package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/data-page-subscription-cleanup.md +41 -0
  37. package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/publish-and-subscribe-events.md +40 -0
  38. package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/pubsub-cleanup.md +38 -0
  39. package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/query-paginated-list-data.md +44 -0
  40. package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/realtime-case-subscription.md +46 -0
  41. package/src/ai/catalog/pconnect-data-subscriptions/cookbooks/refresh-and-update-data.md +41 -0
  42. package/src/ai/catalog/pconnect-forms-and-fields/SKILL.md +44 -0
  43. package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/README.md +36 -0
  44. package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/autosave-tracking.md +45 -0
  45. package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/cascading-dependent-fields.md +51 -0
  46. package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/collect-form-changes-for-manual-save.md +45 -0
  47. package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/custom-field-validators.md +44 -0
  48. package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/discard-changes-and-reset-form.md +41 -0
  49. package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/full-form-validation.md +38 -0
  50. package/src/ai/catalog/pconnect-forms-and-fields/cookbooks/persist-widget-ui-state.md +41 -0
  51. package/src/ai/catalog/pconnect-lists-and-views/SKILL.md +44 -0
  52. package/src/ai/catalog/pconnect-lists-and-views/cookbooks/README.md +35 -0
  53. package/src/ai/catalog/pconnect-lists-and-views/cookbooks/activate-and-switch-container-items.md +52 -0
  54. package/src/ai/catalog/pconnect-lists-and-views/cookbooks/container-item-lifecycle.md +61 -0
  55. package/src/ai/catalog/pconnect-lists-and-views/cookbooks/insert-delete-list-rows.md +40 -0
  56. package/src/ai/catalog/pconnect-lists-and-views/cookbooks/reorder-list-rows.md +39 -0
  57. package/src/ai/catalog/pconnect-lists-and-views/cookbooks/repeating-row-edit.md +39 -0
  58. package/src/ai/catalog/pconnect-lists-and-views/cookbooks/view-personalization.md +60 -0
  59. package/src/ai/catalog/pconnect-navigation-locale-genai/SKILL.md +45 -0
  60. package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/README.md +35 -0
  61. package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/agent-conversation-for-tasks.md +54 -0
  62. package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/bookmarkable-filter-state.md +40 -0
  63. package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/deep-link-semantic-url.md +39 -0
  64. package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/genai-assistant-conversation.md +43 -0
  65. package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/locale-switch-and-relocalize.md +38 -0
  66. package/src/ai/catalog/pconnect-navigation-locale-genai/cookbooks/persist-operator-preferences.md +40 -0
  67. package/src/ai/catalog/references/architecture-overview.md +52 -0
  68. package/src/ai/catalog/references/pconnect-actions-api.md +948 -0
  69. package/src/ai/catalog/references/pconnect-case-info-data-info-localization.md +618 -0
  70. package/src/ai/catalog/references/pconnect-case-validation-utilities.md +238 -0
  71. package/src/ai/catalog/references/pconnect-container-manager.md +215 -0
  72. package/src/ai/catalog/references/pconnect-list-actions.md +250 -0
  73. package/src/ai/catalog/references/pconnect-misc-suggestions-creation.md +231 -0
  74. package/src/ai/catalog/references/pconnect-reference-context-component.md +471 -0
  75. package/src/ai/catalog/references/pconnect-state-config.md +316 -0
  76. package/src/ai/catalog/references/pconnect-validation-api.md +45 -0
  77. package/src/ai/catalog/references/pcore-analytics-genai-details.md +50 -0
  78. package/src/ai/catalog/references/pcore-bootstrap-init-details.md +121 -0
  79. package/src/ai/catalog/references/pcore-bootstrap-registry-routing.md +253 -0
  80. package/src/ai/catalog/references/pcore-case-collaboration-details.md +191 -0
  81. package/src/ai/catalog/references/pcore-case-collaboration-genai.md +264 -0
  82. package/src/ai/catalog/references/pcore-environment-info-details.md +96 -0
  83. package/src/ai/catalog/references/pcore-environment-locale-namespace.md +175 -0
  84. package/src/ai/catalog/references/pcore-messaging-details.md +99 -0
  85. package/src/ai/catalog/references/pcore-misc-details.md +207 -0
  86. package/src/ai/catalog/references/pcore-misc-utilities.md +325 -0
  87. package/src/ai/catalog/references/pcore-rest-data-details.md +164 -0
  88. package/src/ai/catalog/references/pcore-rest-data-messaging.md +308 -0
  89. package/src/ai/catalog/references/pcore-store-context-details.md +40 -0
  90. package/src/ai/catalog/references/pcore-store-context-state.md +130 -0
  91. package/src/ai/index.js +154 -0
  92. package/src/ai/project/.claude/skills/boolean/SKILL.md +43 -0
  93. package/src/ai/project/.claude/skills/case/SKILL.md +58 -0
  94. package/src/ai/project/.claude/skills/create-dx-component/SKILL.md +98 -0
  95. package/src/ai/project/.claude/skills/create-dx-component/assets/PConnProps.d.ts +24 -0
  96. package/src/ai/project/.claude/skills/create-dx-component/assets/create-nonce.ts +5 -0
  97. package/src/ai/project/.claude/skills/create-dx-component/assets/event-utils.ts +18 -0
  98. package/src/ai/project/.claude/skills/create-dx-component/assets/styles.ts +7 -0
  99. package/src/ai/project/.claude/skills/create-dx-component/cookbooks/README.md +28 -0
  100. package/src/ai/project/.claude/skills/create-dx-component/cookbooks/build-a-data-widget.md +281 -0
  101. package/src/ai/project/.claude/skills/create-dx-component/cookbooks/field-with-limits-and-validation.md +156 -0
  102. package/src/ai/project/.claude/skills/create-dx-component/cookbooks/status-badge-field.md +97 -0
  103. package/src/ai/project/.claude/skills/create-dx-component/references/accessibility.md +71 -0
  104. package/src/ai/project/.claude/skills/create-dx-component/references/choosing-type-and-subtype.md +79 -0
  105. package/src/ai/project/.claude/skills/create-dx-component/references/cli-workflow.md +125 -0
  106. package/src/ai/project/.claude/skills/create-dx-component/references/component-patterns.md +241 -0
  107. package/src/ai/project/.claude/skills/create-dx-component/references/config-schema.md +296 -0
  108. package/src/ai/project/.claude/skills/create-dx-component/references/cosmos-components.md +137 -0
  109. package/src/ai/project/.claude/skills/create-dx-component/references/field-behavior.md +155 -0
  110. package/src/ai/project/.claude/skills/create-dx-component/references/field-essentials.md +90 -0
  111. package/src/ai/project/.claude/skills/create-dx-component/references/field-subtypes-extra.md +68 -0
  112. package/src/ai/project/.claude/skills/create-dx-component/references/localization.md +30 -0
  113. package/src/ai/project/.claude/skills/create-dx-component/references/pcore-pconnect-apis.md +77 -0
  114. package/src/ai/project/.claude/skills/create-dx-component/references/presentation-essentials.md +57 -0
  115. package/src/ai/project/.claude/skills/create-dx-component/references/props-contract.md +182 -0
  116. package/src/ai/project/.claude/skills/create-dx-component/references/state-matrix.md +102 -0
  117. package/src/ai/project/.claude/skills/create-dx-component/references/storybook-pattern.md +262 -0
  118. package/src/ai/project/.claude/skills/create-dx-component/references/styles-pattern.md +54 -0
  119. package/src/ai/project/.claude/skills/create-dx-component/references/template-essentials.md +87 -0
  120. package/src/ai/project/.claude/skills/create-dx-component/references/template-patterns.md +131 -0
  121. package/src/ai/project/.claude/skills/create-dx-component/references/test-pattern.md +215 -0
  122. package/src/ai/project/.claude/skills/create-dx-component/references/ui-gallery-reuse.md +93 -0
  123. package/src/ai/project/.claude/skills/create-dx-component/references/widget-essentials.md +84 -0
  124. package/src/ai/project/.claude/skills/create-dx-component/references/widget-patterns.md +164 -0
  125. package/src/ai/project/.claude/skills/currency/SKILL.md +46 -0
  126. package/src/ai/project/.claude/skills/date/SKILL.md +46 -0
  127. package/src/ai/project/.claude/skills/decimal/SKILL.md +49 -0
  128. package/src/ai/project/.claude/skills/details/SKILL.md +60 -0
  129. package/src/ai/project/.claude/skills/email/SKILL.md +42 -0
  130. package/src/ai/project/.claude/skills/field/SKILL.md +68 -0
  131. package/src/ai/project/.claude/skills/form/SKILL.md +51 -0
  132. package/src/ai/project/.claude/skills/generate-component-set/SKILL.md +80 -0
  133. package/src/ai/project/.claude/skills/generate-component-set/component-manifest.json +161 -0
  134. package/src/ai/project/.claude/skills/identify-components/SKILL.md +76 -0
  135. package/src/ai/project/.claude/skills/integer/SKILL.md +45 -0
  136. package/src/ai/project/.claude/skills/page/SKILL.md +60 -0
  137. package/src/ai/project/.claude/skills/page-widget/SKILL.md +55 -0
  138. package/src/ai/project/.claude/skills/percentage/SKILL.md +52 -0
  139. package/src/ai/project/.claude/skills/phone/SKILL.md +44 -0
  140. package/src/ai/project/.claude/skills/picklist/SKILL.md +50 -0
  141. package/src/ai/project/.claude/skills/plan-dx-component/SKILL.md +51 -0
  142. package/src/ai/project/.claude/skills/plan-dx-component/references/design-system-mapping.md +108 -0
  143. package/src/ai/project/.claude/skills/plan-dx-component/references/intake.md +146 -0
  144. package/src/ai/project/.claude/skills/plan-dx-component/references/plan-template.md +76 -0
  145. package/src/ai/project/.claude/skills/plan-dx-component/references/requirements-template.md +88 -0
  146. package/src/ai/project/.claude/skills/presentation/SKILL.md +61 -0
  147. package/src/ai/project/.claude/skills/publish-library/SKILL.md +106 -0
  148. package/src/ai/project/.claude/skills/radiobuttons/SKILL.md +51 -0
  149. package/src/ai/project/.claude/skills/review-component/SKILL.md +49 -0
  150. package/src/ai/project/.claude/skills/review-component/references/checklist.md +77 -0
  151. package/src/ai/project/.claude/skills/template/SKILL.md +60 -0
  152. package/src/ai/project/.claude/skills/text/SKILL.md +45 -0
  153. package/src/ai/project/.claude/skills/update-dx-component/SKILL.md +56 -0
  154. package/src/ai/project/.claude/skills/update-dx-component/references/maintenance.md +43 -0
  155. package/src/ai/project/.claude/skills/url/SKILL.md +46 -0
  156. package/src/ai/project/.claude/skills/validate-component/SKILL.md +78 -0
  157. package/src/ai/project/.claude/skills/validate-component/references/runtime-troubleshooting.md +56 -0
  158. package/src/ai/project/.claude/skills/validate-component/scripts/check-component.mjs +327 -0
  159. package/src/ai/project/.claude/skills/widget/SKILL.md +59 -0
  160. package/src/ai/project/.gemini/settings.json +5 -0
  161. package/src/ai/project/AGENTS.md +74 -0
  162. package/src/ai/readme-section.md +91 -0
  163. package/src/cli.js +48 -7
  164. package/src/constants.js +54 -53
  165. package/src/internal-tests.js +27 -0
  166. package/src/tasks/ai-toggle/index.js +46 -0
  167. package/src/tasks/authenticate/helper.js +38 -38
  168. package/src/tasks/authenticate/index.js +17 -15
  169. package/src/tasks/build-all/helper.js +4 -4
  170. package/src/tasks/build-all/index.js +7 -7
  171. package/src/tasks/build-comp/helper.js +17 -17
  172. package/src/tasks/build-comp/index.js +10 -10
  173. package/src/tasks/build-jest-assets/index.js +7 -9
  174. package/src/tasks/build-lib/helper.js +8 -8
  175. package/src/tasks/build-lib/index.js +8 -8
  176. package/src/tasks/bundle/builder/index.js +9 -12
  177. package/src/tasks/bundle/builder/modules.js +8 -9
  178. package/src/tasks/bundle/builder/paths.js +2 -19
  179. package/src/tasks/bundle/builder/webpack.config.js +60 -77
  180. package/src/tasks/bundle/index.js +8 -8
  181. package/src/tasks/create/index.js +35 -35
  182. package/src/tasks/create/templates/Constellation/Field/Boolean/index.tsx.mustache +1 -36
  183. package/src/tasks/create/templates/Constellation/Field/Date/date.ts.mustache +2 -2
  184. package/src/tasks/create/templates/Constellation/Field/Date/index.tsx.mustache +2 -27
  185. package/src/tasks/create/templates/Constellation/Field/DateTime/date-utils.ts.mustache +2 -2
  186. package/src/tasks/create/templates/Constellation/Field/DateTime/date.ts.mustache +2 -2
  187. package/src/tasks/create/templates/Constellation/Field/DateTime/index.tsx.mustache +2 -35
  188. package/src/tasks/create/templates/Constellation/Field/Decimal/index.tsx.mustache +3 -36
  189. package/src/tasks/create/templates/Constellation/Field/Decimal-Currency/index.tsx.mustache +4 -39
  190. package/src/tasks/create/templates/Constellation/Field/Decimal-Percentage/index.tsx.mustache +4 -53
  191. package/src/tasks/create/templates/Constellation/Field/Icon-Button-URL/index.tsx.mustache +5 -5
  192. package/src/tasks/create/templates/Constellation/Field/Integer/index.tsx.mustache +3 -36
  193. package/src/tasks/create/templates/Constellation/Field/Picklist/index.tsx.mustache +7 -42
  194. package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/component-constants.ts +1 -1
  195. package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/date.ts.mustache +0 -2
  196. package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/embed-utils.ts.mustache +1 -1
  197. package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/index.tsx.mustache +11 -11
  198. package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/repeat-utils.ts.mustache +3 -13
  199. package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/textformat-utils.tsx.mustache +2 -3
  200. package/src/tasks/create/templates/Constellation/Field/Picklist-Autocomplete/utils.ts.mustache +28 -28
  201. package/src/tasks/create/templates/Constellation/Field/Picklist-RadioButtons/index.tsx.mustache +2 -2
  202. package/src/tasks/create/templates/Constellation/Field/Picklist-RadioButtons/textformat-utils.tsx.mustache +2 -3
  203. package/src/tasks/create/templates/Constellation/Field/Text/index.tsx.mustache +4 -33
  204. package/src/tasks/create/templates/Constellation/Field/Text-Email/index.tsx.mustache +3 -33
  205. package/src/tasks/create/templates/Constellation/Field/Text-Input/index.tsx.mustache +3 -31
  206. package/src/tasks/create/templates/Constellation/Field/Text-Paragraph/index.tsx.mustache +3 -31
  207. package/src/tasks/create/templates/Constellation/Field/Text-Phone/index.tsx.mustache +3 -35
  208. package/src/tasks/create/templates/Constellation/Field/Text-URL/index.tsx.mustache +3 -33
  209. package/src/tasks/create/templates/Constellation/Field/Text-URL/text-url.tsx.mustache +2 -3
  210. package/src/tasks/create/templates/Constellation/Field/TimeofDay/index.tsx.mustache +2 -35
  211. package/src/tasks/create/templates/Constellation/Field/TimeofDay/time-of-day.ts.mustache +2 -2
  212. package/src/tasks/create/templates/Constellation/Template/DETAILS/Avatar.tsx.mustache +19 -15
  213. package/src/tasks/create/templates/Constellation/Template/DETAILS/Operator.tsx.mustache +6 -6
  214. package/src/tasks/create/templates/Constellation/Template/DETAILS/demo.stories.tsx.mustache +1 -1
  215. package/src/tasks/create/templates/Constellation/Template/DETAILS/index.tsx.mustache +4 -8
  216. package/src/tasks/create/templates/Constellation/Template/DETAILS/mock.ts.mustache +9 -9
  217. package/src/tasks/create/templates/Constellation/Template/DETAILS/utils.js.mustache +4 -8
  218. package/src/tasks/create/templates/Constellation/Template/DETAILS-region/Avatar.tsx.mustache +19 -15
  219. package/src/tasks/create/templates/Constellation/Template/DETAILS-region/Operator.tsx.mustache +6 -6
  220. package/src/tasks/create/templates/Constellation/Template/DETAILS-region/demo.stories.tsx.mustache +1 -1
  221. package/src/tasks/create/templates/Constellation/Template/DETAILS-region/index.tsx.mustache +1 -1
  222. package/src/tasks/create/templates/Constellation/Template/DETAILS-region/mock.ts.mustache +9 -9
  223. package/src/tasks/create/templates/Constellation/Template/DETAILS-region/utils.ts.mustache +4 -8
  224. package/src/tasks/create/templates/Constellation/Template/FORM/demo.stories.tsx.mustache +8 -8
  225. package/src/tasks/create/templates/Constellation/Template/FORM-region/demo.stories.tsx.mustache +8 -8
  226. package/src/tasks/create/templates/Constellation/Template/PAGE/utils.ts.mustache +4 -9
  227. package/src/tasks/create/templates/Constellation/Widget/CASE/demo.test.tsx.mustache +3 -3
  228. package/src/tasks/create/templates/Constellation/Widget/PAGE-CASE/Avatar.tsx.mustache +19 -14
  229. package/src/tasks/create/templates/Constellation/Widget/PAGE-CASE/Operator.tsx.mustache +6 -6
  230. package/src/tasks/create/templates/Constellation/Widget/PAGE-CASE/index.tsx.mustache +1 -1
  231. package/src/tasks/create/templates/Constellation/Widget/PAGE-CASE/mock.ts.mustache +1 -1
  232. package/src/tasks/create/templates/Launchpad/Field/Icon-Button-URL/index.tsx.mustache +5 -5
  233. package/src/tasks/create/templates/Launchpad/Field/Text-Phone/index.tsx.mustache +3 -35
  234. package/src/tasks/create/templates/Launchpad/Field/__components.md +1 -1
  235. package/src/tasks/create/templates/Launchpad/Template/FORM/demo.stories.tsx.mustache +8 -8
  236. package/src/tasks/create/templates/Launchpad/Template/FORM-region/demo.stories.tsx.mustache +8 -8
  237. package/src/tasks/create/templates/Launchpad/Widget/CASE/demo.test.tsx.mustache +3 -3
  238. package/src/tasks/create/templates/Launchpad/Widget/PAGE-CASE/index.tsx.mustache +1 -1
  239. package/src/tasks/create/templates/Launchpad/Widget/PAGE-CASE/mock.ts.mustache +1 -1
  240. package/src/tasks/create-all/index.js +42 -41
  241. package/src/tasks/create-lib/helper.js +13 -13
  242. package/src/tasks/create-lib/index.js +5 -5
  243. package/src/tasks/create-version/helper.js +10 -10
  244. package/src/tasks/create-version/index.js +3 -4
  245. package/src/tasks/delete/helper.js +20 -19
  246. package/src/tasks/delete/index.js +2 -2
  247. package/src/tasks/delete-all/helper.js +26 -25
  248. package/src/tasks/delete-all/index.js +2 -2
  249. package/src/tasks/delete-lib/helper.js +6 -6
  250. package/src/tasks/delete-lib/index.js +6 -6
  251. package/src/tasks/delete-pub/helper.js +18 -18
  252. package/src/tasks/delete-pub/index.js +8 -8
  253. package/src/tasks/delete-version/index.js +2 -2
  254. package/src/tasks/dev-server/index.js +1 -1
  255. package/src/tasks/export-archive/helper.js +21 -21
  256. package/src/tasks/export-archive/index.js +27 -40
  257. package/src/tasks/export-rc/helper.js +34 -34
  258. package/src/tasks/export-rc/index.js +21 -31
  259. package/src/tasks/import-archive/helper.js +39 -39
  260. package/src/tasks/import-archive/index.js +69 -89
  261. package/src/tasks/import-comp/helper.js +8 -8
  262. package/src/tasks/import-comp/index.js +30 -42
  263. package/src/tasks/index.js +5 -0
  264. package/src/tasks/init/Node.gitignore +149 -0
  265. package/src/tasks/init/helper.js +15 -8
  266. package/src/tasks/init/index.js +115 -35
  267. package/src/tasks/init/template/.prettierrc.json +4 -1
  268. package/src/tasks/init/template/.storybook/main.ts +1 -4
  269. package/src/tasks/init/template/.storybook/manager.ts +1 -1
  270. package/src/tasks/init/template/.storybook/preview.tsx +2 -2
  271. package/src/tasks/init/template/.storybook/theme.js +1 -1
  272. package/src/tasks/init/template/.vscode/extensions.json +0 -1
  273. package/src/tasks/init/template/README.md +2 -2
  274. package/src/tasks/init/template/eslint.config.mjs +13 -155
  275. package/src/tasks/init/template/jest.config.cjs +2 -0
  276. package/src/tasks/init/template/package-lock.json +26864 -0
  277. package/src/tasks/init/template/package.json.mustache +19 -74
  278. package/src/tasks/init/template/setupTests.ts +10 -4
  279. package/src/tasks/init/template/tsconfig.json +14 -6
  280. package/src/tasks/internal-test/index.js +21 -0
  281. package/src/tasks/internal-test-full/index.js +15 -0
  282. package/src/tasks/internal-test-functional/index.js +15 -0
  283. package/src/tasks/internal-test-unit/index.js +13 -0
  284. package/src/tasks/linter/index.js +2 -2
  285. package/src/tasks/list/helper.js +41 -40
  286. package/src/tasks/list/index.js +3 -3
  287. package/src/tasks/list-lib/helper.js +5 -5
  288. package/src/tasks/list-lib/index.js +8 -8
  289. package/src/tasks/list-pub/helper.js +23 -16
  290. package/src/tasks/list-pub/index.js +24 -21
  291. package/src/tasks/move/helper.js +8 -8
  292. package/src/tasks/move/index.js +19 -23
  293. package/src/tasks/promote-webpack/index.js +4 -4
  294. package/src/tasks/promote-webpack/webpack.config.js +62 -93
  295. package/src/tasks/publish/helper.js +21 -21
  296. package/src/tasks/publish/index.js +16 -16
  297. package/src/tasks/publish-all/helper.js +20 -20
  298. package/src/tasks/publish-all/index.js +11 -12
  299. package/src/tasks/publish-archive/helper.js +9 -9
  300. package/src/tasks/publish-archive/index.js +12 -14
  301. package/src/tasks/publish-lib/helper.js +3 -3
  302. package/src/tasks/publish-lib/index.js +28 -34
  303. package/src/tasks/quarantine/index.js +8 -8
  304. package/src/tasks/rename/index.js +26 -30
  305. package/src/tasks/rename-lib/index.js +21 -25
  306. package/src/tasks/restore/index.js +8 -8
  307. package/src/tasks/restore-config/index.js +3 -5
  308. package/src/tasks/set-perm/index.js +8 -8
  309. package/src/tasks/show-help/index.js +17 -9
  310. package/src/tasks/show-status/index.js +2 -2
  311. package/src/tasks/store/index.js +8 -8
  312. package/src/tasks/switch-lib/helper.js +7 -7
  313. package/src/tasks/switch-lib/index.js +7 -7
  314. package/src/tasks/switch-version/helper.js +6 -6
  315. package/src/tasks/switch-version/index.js +7 -7
  316. package/src/tasks/update/index.js +1 -1
  317. package/src/tasks/upgrade/index.js +7 -7
  318. package/src/tasks/validator/index.js +49 -203
  319. package/src/util.js +169 -186
  320. package/src/rules/no-pcore-pconnect-in-presentation.js +0 -103
  321. package/src/tasks/init/template/.stylelintrc.json +0 -4
  322. package/src/tasks/init/template/babel.config.cjs +0 -22
  323. package/src/tasks/init/template/cspell.json +0 -14
@@ -0,0 +1,262 @@
1
+ # Storybook Pattern
2
+
3
+ ## Standard Storybook File (demo.stories.tsx)
4
+
5
+ ```typescript
6
+ /* eslint-disable react/jsx-no-useless-fragment */
7
+ import { useState } from 'react';
8
+ import type { Meta, StoryObj } from '@storybook/react';
9
+
10
+ import { configProps, stateProps } from './mock';
11
+ import AcmeLibComponentName from './index';
12
+
13
+ const meta: Meta<typeof AcmeLibComponentName> = {
14
+ title: 'AcmeLibComponentName',
15
+ component: AcmeLibComponentName,
16
+ excludeStories: /.*Data$/
17
+ };
18
+
19
+ export default meta;
20
+ type Story = StoryObj<typeof AcmeLibComponentName>;
21
+
22
+ export const BaseAcmeLibComponentName: Story = (args: any) => {
23
+ const [value, setValue] = useState(configProps.value);
24
+
25
+ const props = {
26
+ value,
27
+ additionalProps: configProps.additionalProps || {},
28
+ getPConnect: () => {
29
+ return {
30
+ getStateProps: () => {
31
+ return stateProps;
32
+ },
33
+ getActionsApi: () => {
34
+ return {
35
+ updateFieldValue: (propName: string, theValue: any) => {
36
+ setValue(theValue);
37
+ },
38
+ triggerFieldChange: () => { /* nothing */ }
39
+ };
40
+ },
41
+ getValidationApi: () => {
42
+ return {
43
+ validate: () => { /* nothing */ }
44
+ };
45
+ },
46
+ getInheritedProps: () => {
47
+ return {};
48
+ },
49
+ getContextName: () => {
50
+ return 'app/primary_1';
51
+ },
52
+ getLocalizationService: () => {
53
+ return {
54
+ getLocalizedText: (val: any) => val
55
+ };
56
+ },
57
+ getValue: (val: any) => val,
58
+ ignoreSuggestion: () => { /* nothing */ },
59
+ acceptSuggestion: () => { /* nothing */ },
60
+ setInheritedProps: () => { /* nothing */ },
61
+ resolveConfigProps: () => { /* nothing */ }
62
+ };
63
+ }
64
+ };
65
+
66
+ return (
67
+ <>
68
+ <AcmeLibComponentName {...props} {...args} />
69
+ </>
70
+ );
71
+ };
72
+
73
+ BaseAcmeLibComponentName.args = {
74
+ label: configProps.label,
75
+ helperText: configProps.helperText,
76
+ testId: configProps.testId,
77
+ readOnly: configProps.readOnly,
78
+ disabled: configProps.disabled,
79
+ required: configProps.required,
80
+ hideLabel: configProps.hideLabel,
81
+ displayMode: configProps.displayMode,
82
+ validatemessage: configProps.validatemessage
83
+ };
84
+ ```
85
+
86
+ ## Controls (argTypes)
87
+
88
+ Give the story meta `argTypes` so the Storybook controls panel is usable. Every authoring property in `config.json` (except platform-handled formats such as `VISIBILITY`, and `GROUP` wrappers) gets an entry; `check-component.mjs` warns about any that are missing.
89
+
90
+ | `config.json` format | `argTypes` entry |
91
+ | --- | --- |
92
+ | `TEXT` | `{ control: 'text' }` |
93
+ | `BOOLEAN` | `{ control: 'boolean' }` |
94
+ | `NUMBER` | `{ control: { type: 'number', min, max, step } }`, copying `min` and `max` from `config.json` |
95
+ | `SELECT` | `{ options: [keys], control: { type: 'select', labels: { key: 'value' } } }`, built from `source` |
96
+ | `DATASOURCE`, objects, `getPConnect` | `{ table: { disable: true } }` |
97
+
98
+ - A prop with a fixed set of values (`mode`, `wheelType`, `variant`) gets a `select` control with `options` and human-readable `labels`, never a free-text box.
99
+ - Seed the base story's `args` from `mock.ts` `configProps`, whose values match the `config.json` defaults, so the panel opens on the authored defaults.
100
+ - List the component's own props first, then common DX props such as `testId` and `hideLabel`.
101
+ - Set explicit defaults in the story `args` for common DX props (`hideLabel: false`, `testId: ''`) and expose `hideLabel` as one boolean control.
102
+ - Hide what cannot be edited in the panel (`getPConnect`, object props such as `datasource`) with `table: { disable: true }`.
103
+
104
+ ```typescript
105
+ const meta: Meta<typeof AcmeLibMyWidget> = {
106
+ title: 'AcmeLibMyWidget',
107
+ component: AcmeLibMyWidget,
108
+ excludeStories: /.*Data$/,
109
+ argTypes: {
110
+ mode: {
111
+ options: ['game', 'business'],
112
+ control: { type: 'select', labels: { game: 'Game (place bets)', business: 'Business (pick an item)' } }
113
+ },
114
+ hideLabel: { control: 'boolean' },
115
+ getPConnect: { table: { disable: true } }
116
+ }
117
+ };
118
+ ```
119
+
120
+ ## Widget Storybook Pattern (with PCore mocking)
121
+
122
+ For widgets that use `PCore` global APIs:
123
+
124
+ ```typescript
125
+ /* eslint-disable react/jsx-no-useless-fragment */
126
+ import type { Meta, StoryObj } from '@storybook/react';
127
+ import AcmeLibMyWidget from './index';
128
+ import mockData from './mock';
129
+
130
+ const meta: Meta<typeof AcmeLibMyWidget> = {
131
+ title: 'AcmeLibMyWidget',
132
+ component: AcmeLibMyWidget,
133
+ excludeStories: /.*Data$/
134
+ };
135
+
136
+ export default meta;
137
+ type Story = StoryObj<typeof AcmeLibMyWidget>;
138
+
139
+ if (!window.PCore) {
140
+ window.PCore = {} as any;
141
+ }
142
+
143
+ export const BaseAcmeLibMyWidget: Story = (args: any) => {
144
+ window.PCore.getConstants = () => {
145
+ return { CASE_INFO: { CASE_INFO_ID: 'caseInfo.ID' } } as any;
146
+ };
147
+
148
+ window.PCore.getLocaleUtils = () => {
149
+ return { getLocaleValue: (value: any) => value } as any;
150
+ };
151
+
152
+ window.PCore.getDataApiUtils = () => {
153
+ return {
154
+ getData: () => new Promise(resolve => resolve(mockData))
155
+ } as any;
156
+ };
157
+
158
+ const props = {
159
+ getPConnect: () => {
160
+ return {
161
+ getValue: (value: any) => value,
162
+ getContextName: () => 'app/primary_1',
163
+ getLocalizationService: () => ({
164
+ getLocalizedText: (value: any) => value
165
+ }),
166
+ getActionsApi: () => ({
167
+ updateFieldValue: () => {},
168
+ triggerFieldChange: () => {}
169
+ }),
170
+ ignoreSuggestion: () => {},
171
+ acceptSuggestion: () => {},
172
+ setInheritedProps: () => {},
173
+ resolveConfigProps: () => {}
174
+ };
175
+ }
176
+ };
177
+
178
+ return (
179
+ <>
180
+ <AcmeLibMyWidget {...props} {...args} />
181
+ </>
182
+ );
183
+ };
184
+
185
+ BaseAcmeLibMyWidget.args = {
186
+ label: 'Widget Title'
187
+ };
188
+ ```
189
+
190
+ ## Template Storybook Pattern
191
+
192
+ For templates with children:
193
+
194
+ ```typescript
195
+ import type { Meta, StoryObj } from '@storybook/react';
196
+ import AcmeLibMyTemplate from './index';
197
+ import { configProps } from './mock';
198
+
199
+ const meta: Meta<typeof AcmeLibMyTemplate> = {
200
+ title: 'AcmeLibMyTemplate',
201
+ component: AcmeLibMyTemplate,
202
+ excludeStories: /.*Data$/
203
+ };
204
+
205
+ export default meta;
206
+ type Story = StoryObj<typeof AcmeLibMyTemplate>;
207
+
208
+ export const BaseAcmeLibMyTemplate: Story = (args: any) => {
209
+ const props = {
210
+ ...configProps,
211
+ children: [
212
+ <div key="1">Child 1</div>,
213
+ <div key="2">Child 2</div>
214
+ ],
215
+ getPConnect: () => ({
216
+ getInheritedProps: () => ({}),
217
+ getActionsApi: () => ({
218
+ updateFieldValue: () => {},
219
+ triggerFieldChange: () => {}
220
+ }),
221
+ getValidationApi: () => ({ validate: () => {} })
222
+ })
223
+ };
224
+
225
+ return <AcmeLibMyTemplate {...props} {...args} />;
226
+ };
227
+
228
+ BaseAcmeLibMyTemplate.args = {
229
+ label: 'Template Label',
230
+ showLabel: true,
231
+ NumCols: '2'
232
+ };
233
+ ```
234
+
235
+ ## `mock.ts` rules
236
+
237
+
238
+ Export the sample props the story needs, at minimum `configProps` and, for components bound to a property, `stateProps` (scaffolds often export more, such as sample data or metadata):
239
+
240
+ ```typescript
241
+ export const configProps = {
242
+ label: 'Spin Wheel',
243
+ names: 'Alice, Bob, Carol, Dan, Eve',
244
+ spinDuration: 800
245
+ };
246
+
247
+ export const stateProps = {
248
+ value: '.Names'
249
+ };
250
+ ```
251
+
252
+ - `configProps` keys mirror `config.json` property names, with fully resolved values — never the `@L` prefix.
253
+ - `stateProps.value` is the dot-notation case property path the component binds to.
254
+ - Widget fixtures must be realistic enough that the story renders without a live Pega server.
255
+
256
+ ## Story conventions
257
+
258
+
259
+ - Name the base story `Base<InnerFunctionName>` — `demo.test.tsx` imports it by that name through `composeStories`.
260
+ - If the return is wrapped in a fragment, start the file with `/* eslint-disable react/jsx-no-useless-fragment */`.
261
+ - Empty mock callbacks need a `/* nothing */` comment body to satisfy lint.
262
+ - Story and mock files are excluded from the main ESLint config, but keep them consistent with the rest of the repo anyway.
@@ -0,0 +1,54 @@
1
+ # Styles Pattern (`styles.ts`)
2
+
3
+ > Part of the [create-dx-component skill](../SKILL.md).
4
+
5
+ ## Required shape
6
+
7
+
8
+ ```typescript
9
+ import styled, { css } from 'styled-components';
10
+
11
+ export default styled.div(() => {
12
+ return css`
13
+ margin: 0px 0;
14
+ `;
15
+ });
16
+ ```
17
+
18
+ - Default-export a single `styled.div`.
19
+ - Import both `styled` and `css`.
20
+ - Consume it in `index.tsx` as `StyledWrapper` wrapping the component's return value.
21
+
22
+ ## Styled-components are a LAST RESORT
23
+
24
+
25
+ The canonical rule lives in [AGENTS.md](../../../../AGENTS.md). What it means *in this file* — the concrete allow and deny lists:
26
+
27
+ Legitimate uses:
28
+
29
+ - keyframe animations, `transform`, `transition`
30
+ - hover/focus/drag states Cosmos does not expose
31
+ - SVG and canvas styling
32
+ - a positional override Cosmos props cannot express
33
+
34
+ Never write rules here for:
35
+
36
+ - layout — use `Flex` or `Grid`
37
+ - cards and panels — use `Card`, `CardHeader`, `CardContent`
38
+ - typography, sizing, or colour of text — use `Text` variants
39
+ - badges and pills — use `Status`, `Tag`, `Count`
40
+ - loading and empty states — use `Progress`, `EmptyState`
41
+
42
+ ## Other rules
43
+
44
+
45
+ - Never use inline `style={{ ... }}` in `index.tsx`. All custom CSS belongs here.
46
+ - Target children by class name from inside the wrapper; do not export additional styled components unless `index.tsx` imports each one.
47
+ - Every rule must apply to an element that actually renders. Delete selectors for markup that no longer exists — dead CSS is dead code.
48
+ - Prefer Cosmos design tokens over hardcoded colours and spacing.
49
+
50
+ ## The theme is not available here
51
+
52
+ `@pega/cosmos-react-core` bundles its own nested copy of `styled-components`, so `theme.base` is `undefined` in this file and `theme.base.palette` throws. Read the theme in `index.tsx` with `useTheme()` and pass the values in as transient props (`$error`, `$success`). The worked example is in [cosmos-components.md](./cosmos-components.md#styled-components-theme-does-not-cross-the-boundary).
53
+
54
+ Valid `base.palette` keys include `primary-background`, `secondary-background`, `foreground-color`, `app-background`, `brand-primary`, `urgent`, `warn`, `success`, `pending`, `info`, `interactive`, `border-line`. Props-driven styled components are also the right home for state-driven `transform`, `transition` and animation values, which keeps them out of inline styles.
@@ -0,0 +1,87 @@
1
+ # Template essentials
2
+
3
+ Read this instead of the deep references for a typical template. Open a deep reference only for the cases listed at the end.
4
+
5
+ ## Before you code
6
+
7
+ - States to cover (mark one not applicable with a reason): all regions populated, optional region empty, required region empty, one child unavailable, long child content, narrow width, wide width, all children of a region hidden, read-only parent, nested template, missing or string config (`NumCols`). Add "active tab hidden or removed" for tabs.
8
+ - Each covered state gets a `mock.ts` fixture, a story and at least one test assertion.
9
+ - Start from the scaffolded files; the scaffold is a working sample, replace demo content that does not serve the request. Delete scaffold helpers you do not use.
10
+
11
+ ## index.tsx
12
+
13
+ - `interface Props extends PConnFieldProps` with `children: any[]` and optional props named exactly like the `config.json` properties (`NumCols`, `showLabel`, ...). Export `withConfiguration(AcmeLibMyTemplate)`; keep `import '../shared/create-nonce';`. `PCore` is a global; do not import it.
14
+ - `children` is one element per region, not per field. Normalize with `[props.children].flat(Infinity).filter(isValidElement)` and guard an empty value.
15
+ - Find a region by `region.props.getPConnect().getRawMetadata().name` (`A`, `B`, `C`, `Fields`), not by index; if `find` returns `undefined`, fall back to `children[0]`. Never rename scaffold regions.
16
+ - Editable layout: render `children` straight into a Cosmos `Grid`. Read-only or per-field layout: go one level down with `region.props.getPConnect().getChildren()`, render each with `getPConnect().getComponent()` in `useMemo`, and read labels with `resolveConfigProps(getConfigProps())`.
17
+ - Merge inherited props over your own: `{ label, showLabel, ...getPConnect().getInheritedProps() }`; inherited wins.
18
+ - Show the label when `showLabel` is true, or unset and editable; in display mode unless `showLabel === false`. No label, no heading.
19
+ - `NumCols` is a string: `parseInt(NumCols, 10) || 1`; `Grid` `gap` is a Cosmos spacing unit (for example `2`), not pixels. Normalize flags with `true | 'true'`; guard numbers with `Number.isFinite`.
20
+ - Branch on both `readOnly` and `displayMode === 'DISPLAY_ONLY'` (and `mode === 'editable'` on embedded data views). A DETAILS or read-only template forces each region child during render, with the same values every time:
21
+
22
+ ```typescript
23
+ child.props.getPConnect().setInheritedProp('readOnly', true);
24
+ child.props.getPConnect().setInheritedProp('displayMode', 'DISPLAY_ONLY');
25
+ ```
26
+
27
+ - Columns: `Grid` with `container={{ cols: 'repeat(N, minmax(0, 1fr))', gap }}`; column count and gap come from `config.json`, never hard-coded pixels. Block children (text areas, groups, tables) span the row. Wrap by container width, not viewport; prefer `Grid` responsive props or `useBreakpoint`.
28
+ - Do not wrap children in extra `div`s, set `100vh`, or add landmarks. Reading order matches visual order.
29
+ - Hidden children: hide the whole cell; when all children of a region or view are hidden, its heading disappears too. Show `EmptyState` when every region is empty.
30
+ - Render the elements the platform created; do not add your own error boundary around them.
31
+ - Use `FieldGroup` (with `name`) only when there is a label; show instructions only with a heading. Headings stay sequential: section `h2`, nested `h3`.
32
+ - Tabs: Cosmos `Tabs` and `TabPanel`; do not reimplement them. Keep tab ids unique and stable; fall back to the first visible tab.
33
+ - No secrets, tokens or per-environment URLs anywhere in the component folder (`check-component.mjs` fails).
34
+ - Never mutate `getRawMetadata()` objects; clone first. Call hooks before any early return. Key children by `getRawMetadata().config.value` or `.name`, never a random id.
35
+ - Localize labels with `PCore.getLocaleUtils().getLocaleValue(label, undefined, localeReference)`; `getLocalizedValue` is deprecated.
36
+ - Cosmos-first, without deep imports from `lib/components/...`; check any new Cosmos prop in its `.d.ts` in `node_modules`. Look up every `PCore` and `pConn` call in [pcore-pconnect-apis.md](./pcore-pconnect-apis.md); use only documented methods.
37
+ - No inline `style={{ ... }}`, `dangerouslySetInnerHTML`, `console`, nested ternaries, `++` or dead code.
38
+
39
+ ## config.json
40
+
41
+ - Start from the scaffolded file, never from memory. Keep `type: "Template"`, the scaffolded `subtype`, the region `CONTENTPICKER` entries and `{ "format": "INSTRUCTIONS" }`.
42
+ - Region and layout names are PascalCase or a single letter (`NumCols`, `Fields`, `A`); renaming one breaks saved views.
43
+ - `NumCols` is a `SELECT` with keys `'1'`, `'2'`, `'3'` and a `defaultValue`. Set the `showLabel` default in `defaultConfig`.
44
+ - Add only properties the user confirmed; `index.tsx` reads every named one, or `check-component.mjs` fails (`CONTENTPICKER`, `INSTRUCTIONS`, `VISIBILITY` and similar are platform-handled).
45
+ - `validate-schema` rejects missing required keys, a wrong subtype, a property lacking `name`, `label` or `format`, and duplicates. It does not check `format`: use only scaffold formats. `SELECT` needs `source: [{ key, value }]`; `GROUP` has no `name`. Labels are sentence case without `@L`.
46
+
47
+ ## styles.ts
48
+
49
+ - Keep the single default-exported `styled.div` wrapper.
50
+ - Rules only for what Cosmos cannot express; never grid, flex, card or gap rules.
51
+ - The theme is undefined here: `useTheme()` in `index.tsx`, pass values as transient props.
52
+ - Hide a grid item rather than relying on margins; delete selectors for markup that is gone.
53
+
54
+ ## mock.ts and demo.stories.tsx
55
+
56
+ - `mock.ts` exports `configProps` (`label`, `showLabel`, `NumCols`, resolved values, never `@L`).
57
+ - Stories pass a `children` array and a fake `getPConnect` with exactly the methods the template calls (`getInheritedProps`, ...). For region or read-only behavior, fake children whose `getPConnect` provides `getRawMetadata`, `getChildren` and `setInheritedProp`.
58
+ - Base story is `Base<InnerFunctionName>`; one story per covered state.
59
+ - Meta `argTypes` gives every `config.json` property a matching control ([storybook-pattern.md](./storybook-pattern.md#controls-argtypes)); hide `getPConnect`.
60
+
61
+ ## demo.test.tsx
62
+
63
+ - Query by role and accessible name (`getByRole('group', { name: 'Contact' })`); needing a test id is an accessibility finding. Use `fireEvent` (no `user-event`).
64
+ - One assertion per covered state: all regions populated; an empty optional region; all children hidden hides the heading; read-only calls `setInheritedProp` with both `readOnly` and `displayMode`; column count from config, including `'2'` and a missing value; region found by name when the order differs.
65
+ - Toggle props with `rerender`; never weaken an assertion.
66
+
67
+ ## localizations.json
68
+
69
+ - A template that shows its own text lists every string under `fields` as `"English text": "English text"`, in step with the code.
70
+ - Use whole sentences with `{0}` placeholders; plurals are separate keys; do not translate data or cache translated text.
71
+
72
+ ## Open a deep reference only when
73
+
74
+ | Situation | Read |
75
+ | --- | --- |
76
+ | Container-width columns, nested templates, label alignment, field groups, tabs, PAGE layouts, hidden-child re-render | [template-patterns.md](./template-patterns.md) |
77
+ | A FORM, DETAILS or PAGE specific rule | [form](../../form/SKILL.md), [details](../../details/SKILL.md), [page](../../page/SKILL.md) |
78
+ | A config format beyond the scaffold's, visibility, bindings | [config-schema.md](./config-schema.md) |
79
+ | A failing test, jsdom stubs, a fuller story fake | [test-pattern.md](./test-pattern.md), [storybook-pattern.md](./storybook-pattern.md) |
80
+ | A Cosmos component you have not used, theme palette keys | [cosmos-components.md](./cosmos-components.md), [styles-pattern.md](./styles-pattern.md) |
81
+ | Headings, focus, reflow, manual checks | [accessibility.md](./accessibility.md) |
82
+ | Placeholders, plurals, formatting | [localization.md](./localization.md) |
83
+ | Full prop list or skeleton | [props-contract.md](./props-contract.md), [component-patterns.md](./component-patterns.md) |
84
+ | The full state list | [state-matrix.md](./state-matrix.md) |
85
+ | An unusual layout | [choosing-type-and-subtype.md](./choosing-type-and-subtype.md) |
86
+
87
+ Finish with `node .claude/skills/validate-component/scripts/check-component.mjs <Org>_<Library>_<Name>`; see [cli-workflow.md](./cli-workflow.md).
@@ -0,0 +1,131 @@
1
+ # Template Patterns
2
+
3
+ How production Constellation templates receive children, read configuration, force read-only, lay out columns, group fields and handle hidden children. States are in [state-matrix.md](./state-matrix.md); the code skeleton is in [component-patterns.md](./component-patterns.md); the `config.json` shapes are in [config-schema.md](./config-schema.md).
4
+
5
+ Use only PCore/PConnect methods documented in the [API catalog](./pcore-pconnect-apis.md). Where this file names a method the catalog does not document, it says so. Cosmos props and components come from a newer Cosmos than customers may have installed, so check the `.d.ts` in `node_modules/@pega/cosmos-react-core` and `@pega/cosmos-react-work` first.
6
+
7
+ ## Children are regions
8
+
9
+ The `children` prop is **one element per region**, not one per field. Look at what the scaffold does before choosing a layout:
10
+
11
+ - **Editable layout:** render `children` straight into the Cosmos `Grid`. The platform has already resolved each region; this is what the FORM scaffold does.
12
+ - **Read-only layout:** go one level down. A region's fields are `region.props.getPConnect().getChildren()`, which returns `[{ getPConnect }]`. Render each with `getPConnect().getComponent()`, and read its label and settings with `getPConnect().resolveConfigProps(getPConnect().getConfigProps())`. The DETAILS and FORM scaffolds do this in `DetailsRender.tsx`.
13
+ - **Per-field layout** (column spans, per-field visibility, label/value pairs) always needs the second form, because the region element hides the fields.
14
+
15
+ Normalize the prop first: `const children = [props.children].flat(Infinity).filter(isValidElement)`.
16
+
17
+ Find a region by name, not by position: `region.props.getPConnect().getRawMetadata().name`. The generic region names are `A`, `B` and `C` (the PAGE, DETAILS and FORM-region scaffolds), with `Fields` for a single-region form. Fall back to the first child only if the named region is missing. Do not rename these in a copied scaffold; saved views depend on them.
18
+
19
+ Memoize the element you get from `getComponent()` (`useMemo(() => pConn.getComponent(), [])`). A new element every render remounts the child and loses its focus and state.
20
+
21
+ A node whose raw metadata `type` is `reference` is a view reference; its content is available through `getReferencedViewPConnect().getPConnect()`. Render a reference child directly, without wrapping it in a label/value pair. Test it with `getRawMetadata().type === 'reference'`, not with private fields.
22
+
23
+ Never mutate raw child metadata (`getRawMetadata()` objects). Clone it first; a mutation leaks across renders.
24
+
25
+ ## Reading configuration
26
+
27
+ - Merge inherited props over your own: `const propsToUse = { label, showLabel, ...getPConnect().getInheritedProps() };`. Inherited values win, because a parent view reference can override a child view's heading.
28
+ - Show the label when `showLabel` is true, or when it is unset and the view is editable. In display mode, show it unless `showLabel === false`. Return no heading when there is no label.
29
+ - Numbers and booleans arrive as strings. `NumCols` is a string select (`'1'`, `'2'`, `'3'`): use `parseInt(NumCols, 10) || 1`. Normalize `true | 'true'` for flags, and guard numeric settings with `Number()` plus `Number.isFinite`.
30
+ - `showLabel` defaults differ by template (a form defaults to false, a details view to true); set the default in `defaultConfig` so the property panel matches.
31
+ - Per-child settings are read with `getConfigProps()`: `visibility`, `displayMode`, and layout hints such as `isFormWidth`, `isContainerWidth` and `detailFVLItem`.
32
+ - Localize labels with `PCore.getLocaleUtils().getLocaleValue(label, undefined, localeReference)`; `pConn.getLocalizedValue` is deprecated.
33
+
34
+ ## Forcing read-only
35
+
36
+ A DETAILS template must make its fields display-only, and the shipped scaffold does it on every region child:
37
+
38
+ ```typescript
39
+ children.forEach((child) => {
40
+ child.props.getPConnect().setInheritedProp('readOnly', true);
41
+ child.props.getPConnect().setInheritedProp('displayMode', 'DISPLAY_ONLY');
42
+ });
43
+ ```
44
+
45
+ Without this a custom DETAILS template shows editable inputs. It is called during render, so it must be idempotent (same values every render, none that depend on a loop variable). `setInheritedProp` takes an optional third argument in the platform source that carries the prop across nested view boundaries; check the installed typedefs before using it, because the catalog documents two arguments.
46
+
47
+ For a field you create from the template's own configuration (highlighted data), set `field.config.displayMode = 'DISPLAY_ONLY'` on a copy of the metadata before `getPConnect().createComponent(...)`, as the scaffold's `HighlightRender` does.
48
+
49
+ Branch on **both** `readOnly` and `displayMode === 'DISPLAY_ONLY'`. Do not lay out read-only values with the editable grid (see label alignment below).
50
+
51
+ ## Columns and responsive layout
52
+
53
+ - Build columns from `Grid` with `minmax(0, 1fr)` tracks. For fixed ratios: `narrowWide` is `minmax(0, 1fr) minmax(0, 2fr)` and `wideNarrow` is `minmax(0, 2fr) minmax(0, 1fr)`. Use those names for a layout property.
54
+ - **Wrap by container width, not viewport width.** A template can sit in a narrow side panel or a modal, so a viewport media query lies. Measure the template's own container with a `ResizeObserver` (create it in `useLayoutEffect` to avoid a first-paint flash, and `disconnect()` it in cleanup). Collapse to one column when the container is narrower than `minFieldWidth * columns + gaps` (production uses a 16rem minimum field width, and a 620px container for two columns in a tab). Compute `rem` in pixels inside the hook, not at module load.
55
+ - Cosmos also offers `useBreakpoint('md')` and responsive `Grid` props (`md={{ container: { cols } }}`). Prefer `Grid` over a hand-written media query.
56
+ - **Block children span the row.** Large controls (`TextArea`, `RichText`, `RadioButtons`, `Checkbox` groups, `Attachment`, `Address`, `Group`, embedded tables and references) get `item={{ colStart: '1', colEnd: cols + 1 }}`. A field config flag `isFormWidth` does the same. Tables (`isContainerWidth`) are lifted out of the column grid into their own block.
57
+ - A long value goes **stacked** (label above) instead of inline: a text area or rich text of about 60 characters or more, an image URL, a map. Otherwise inline.
58
+ - A theme setting that places helper text above the field forces a single column.
59
+ - Nested templates: an embedded view inside a form normally inherits the outer column count rather than starting its own grid. Add an `inheritParentLayout` boolean (and, as the scaffold does, a `templateOverrideMode` select with `USE_TEMPLATE` / `IGNORE_TEMPLATE`) if the template can be nested. Share the outer count through your own React context between your own templates.
60
+ - Do not set `100vh` or a page height. The shell owns scrolling.
61
+
62
+ ### Label alignment in read-only lists
63
+
64
+ Put consecutive simple fields in **one** `FieldValueList` (or the Cosmos `Details` list) so labels share a column. Separate lists break the alignment. Start a new list at a non-simple child (a nested view, table, group or editable reference). `@pega/cosmos-react-work` exports `Details`, `DetailsList` and `DetailsContext`, which already handle container-width columns, heading depth, `narrowWide` / `wideNarrow` arrangement, an empty-column `EmptyState` and label-column alignment; check whether the installed version has them before hand-building. A Checkbox's label comes from `caption`, not `label`.
65
+
66
+ ## Field groups and headings
67
+
68
+ - `FieldGroup` with a `name` renders a `fieldset` with a `legend`; without a name it is a plain `div`. The legend is not a heading unless you pass `headingTag`. It also supports `description`, `collapsed` with `onToggleCollapsed` (the button has `aria-expanded`), `status='error'` and `variant='form-group'`.
69
+ - `FieldGroupList` renders an ordered list of groups (a repeating section) with `id`, `headingTag`, `status`, `collapsed` and `onDelete` per item.
70
+ - Wrap in a `FieldGroup` only when there is a label to show. Show **instructions only when a heading is shown** (WCAG 2.4.6 and 3.3.2). The `{ "format": "INSTRUCTIONS" }` property yields an `instructions` prop that can be `'casestep'`, `'none'`, a string, or `{ htmlContent, messageType, dismissBanner }` (`Caution`, `Information` and `Good` map to `Banner` variants `warning`, `info` and `success`). An unprocessed `'@PARAGRAPH ...'` string should be hidden, not shown.
71
+ - Heading levels: the page template owns the `h1`; a top-level section is `h2`; nested content is `h3` and below. Keep them sequential by `Text variant` or `headingTag`.
72
+ - Collapsible row state: keep a `Map<rowId, boolean>` keyed by a stable id (the unique field value, else the index). Seed existing rows from the setting, start rows added later expanded, and no cleanup is needed on delete.
73
+
74
+ ## Hidden, invisible and empty children
75
+
76
+ - A child with `visibility: false` renders `null`, but your wrapper cell stays and leaves an empty gap. Hide the whole cell, and hide the whole block when every cell is hidden.
77
+ - A view or group whose children are all hidden collapses, and its heading must disappear too. Write a local `hasVisibleChild` over `getChildren()` using `isVisible()` and `getConfigProps().visibility !== false`.
78
+ - A template that reads `isVisible()` in render may not re-render when a child's visibility flips, because the platform's connect layer is internal. If it matters, register a value with `registerAdditionalProps` (documented) so the template re-renders, and test the flip.
79
+ - Empty states: show `EmptyState` when every region has no children. If every child is an Insight, or a single Pulse, skip the surrounding `Card` so it is not double-wrapped.
80
+ - One broken child does not break its siblings as long as you render the elements the platform created; the platform wraps each in an error boundary. Do not add your own boundary around them, which would hide errors the platform surfaces.
81
+
82
+ ## Tabs
83
+
84
+ Use Cosmos `Tabs` and `TabPanel`. They already provide `role=tablist`, `aria-orientation`, `role=tab` with `aria-selected` and `aria-controls`, a roving `tabIndex`, Arrow-key navigation, `role=tabpanel` with `aria-labelledby`, and `inert` on inactive panels. Do not reimplement them.
85
+
86
+ - `tabs` entries are `{ id, name, count?, errors?, disabled?, href? }`. Ids become DOM ids; keep them unique and stable (`${viewName}-${name}-${index}`, or a unique field value for row tabs).
87
+ - Active tab: keep the current tab if it is still visible, otherwise fall back to the first visible one. Re-run this when visibility or the data changes, so deleting the active tab never leaves a dangling id.
88
+ - Vertical tabs only at `md` and up: `useBreakpoint('md') ? type : 'horizontal'`.
89
+ - Create content lazily for display tabs, and mount all tabs for editable forms (validation needs every field).
90
+ - Persist the active tab with `PCore.getNavigationUtils().setComponentState(key, state)` and read it with `getComponentState`; derive the key from the case and view names. Remove it with `removeComponentState` when it is no longer needed.
91
+ - Style with `[aria-orientation='vertical']` and `[role]` selectors. Do not deep-import Cosmos internals (`StyledTab`, `lib/components/...`); they are not public API.
92
+
93
+ ## PAGE templates
94
+
95
+ Delegate to the public Cosmos page templates: `OneColumnPage`, `TwoColumnPage`, `ThreeColumnPage`, `WideNarrowPage`, `NarrowWidePage`, `TabbedPage` and `DynamicLayoutPage`. Their common props are `title`, `icon`, `actions`, `banners`, `path`, `header`, `utilities` and the region slots `a`, `b`, `c`. Pass region elements straight into the slots.
96
+
97
+ - Offer the layout as a `SELECT` (`one-column`, `two-column`, `narrow-wide`, `wide-narrow`) and show the region B picker only for layouts that use it (`"visibility": "$this.layout == 'two-column'"`).
98
+ - Cosmos owns scrolling, the `md` breakpoint, sticky regions and heading focus. Do not set `document.title` (the platform sets it) and do not move focus to the heading yourself.
99
+ - Add no `<main>` or other landmark; the shell owns them.
100
+
101
+ ## Passing context to children
102
+
103
+ - `setInheritedProp(name, value)` on the template or a child (documented), and `setInheritedConfig` (documented).
104
+ - `registerAdditionalProps({ key: '@P caseInfo.lastUpdateTime' })` pushes a store value in as a prop (documented).
105
+ - Your own React context between your own components, and `DetailsContext` from `@pega/cosmos-react-work` if you use `Details`.
106
+ - Scope pub/sub events to an instance id so two forms on a page do not react to each other (see [widget-patterns.md](./widget-patterns.md)).
107
+ - When a local and an inherited prop collide, the inherited one wins.
108
+
109
+ ## Memoization
110
+
111
+ - `useMemo` the heavy trees (the content element, the tab array, highlighted data) with the real inputs as dependencies. Memoize context values you provide.
112
+ - Call hooks **before** any early return. A read-only early return placed above a hook breaks the call order.
113
+ - Key children by `getRawMetadata().config.value` or `.name`, with the index as a last resort. Do not use a random id (`createUID()` or `crypto.randomUUID()`) as a key; it remounts every render.
114
+
115
+ ## List and table templates
116
+
117
+ Pega's list templates sit on internal libraries and cannot be reproduced by a customer, so there is little to copy. The transferable parts: identify rows by a unique field (or index), and use that id for keys, collapse state, tab ids and deletion (re-find the row by id, because indexes shift); keep the latest values in refs for stable callbacks; subscribe with a per-instance id and always unsubscribe; and when the last row is deleted while focus was inside the table, move focus to the Add button.
118
+
119
+ ## Traps
120
+
121
+ 1. `getComponent()` in render without `useMemo` remounts the child.
122
+ 2. Indexing `children[i]` instead of finding a region by name.
123
+ 3. A section heading shown over an all-hidden view.
124
+ 4. Mutating raw child metadata.
125
+ 5. A `display:none` cell breaking `:last-child` margin logic; with `Grid` gap, hide the item rather than relying on margins.
126
+ 6. `displayMode` also arrives on embedded data views; handle `mode === 'editable'` together with `displayMode`.
127
+ 7. Reading `NumCols` as a number when it is a string.
128
+ 8. Cosmos deep imports from `lib/components/...`.
129
+ 9. Setting the document title or focusing the heading in a PAGE template.
130
+ 10. Calling `setInheritedProp` with a changing value in a loop during render.
131
+ 11. Reading `oneRem` in pixels at module load, and forgetting to disconnect a `ResizeObserver`.