@salesforce/afv-skills 1.7.5 → 1.9.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.
- package/package.json +1 -1
- package/skills/activating-datacloud/CREDITS.md +5 -0
- package/skills/activating-datacloud/README.md +39 -0
- package/skills/activating-datacloud/SKILL.md +118 -0
- package/skills/analyzing-omnistudio-dependencies/CREDITS.md +5 -0
- package/skills/analyzing-omnistudio-dependencies/SKILL.md +477 -0
- package/skills/analyzing-omnistudio-dependencies/references/dependency-patterns.md +508 -0
- package/skills/analyzing-omnistudio-dependencies/references/namespace-guide.md +300 -0
- package/skills/building-omnistudio-callable-apex/CREDITS.md +9 -0
- package/skills/building-omnistudio-callable-apex/README.md +80 -0
- package/skills/building-omnistudio-callable-apex/SKILL.md +276 -0
- package/skills/building-omnistudio-callable-apex/assets/pattern_callable_openinterface.cls +40 -0
- package/skills/building-omnistudio-callable-apex/assets/pattern_callable_vanilla.cls +32 -0
- package/skills/building-omnistudio-callable-apex/assets/pattern_migration.cls +54 -0
- package/skills/building-omnistudio-callable-apex/assets/pattern_openinterface.cls +45 -0
- package/skills/building-omnistudio-callable-apex/assets/pattern_test_class.cls +65 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_QuoteByProductCallable/IndustriesCallableException.cls +7 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_QuoteByProductCallable/Industries_QuoteByProductCallable.cls +115 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_QuoteByProductCallable/Industries_QuoteByProductCallableTest.cls +189 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_QuoteByProductCallable/TRANSCRIPT.md +115 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_VlocityOpenInterface2Conversion/IndustriesCallableException.cls +7 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_VlocityOpenInterface2Conversion/MyCustomCallable.cls +74 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_VlocityOpenInterface2Conversion/MyCustomCallableTest.cls +146 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_VlocityOpenInterface2Conversion/MyCustomRemoteClass.cls +16 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_VlocityOpenInterface2Conversion/TRANSCRIPT.md +120 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_VlocityOpenInterfaceConversion/IndustriesCallableException.cls +7 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_VlocityOpenInterfaceConversion/MyCustomCallable.cls +73 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_VlocityOpenInterfaceConversion/MyCustomCallableTest.cls +128 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_VlocityOpenInterfaceConversion/MyCustomVlocityOpenInterface2.cls +23 -0
- package/skills/building-omnistudio-callable-apex/examples/Test_VlocityOpenInterfaceConversion/TRANSCRIPT.md +75 -0
- package/skills/building-omnistudio-datamapper/CREDITS.md +5 -0
- package/skills/building-omnistudio-datamapper/SKILL.md +270 -0
- package/skills/building-omnistudio-datamapper/assets/completion-summary-template.md +28 -0
- package/skills/building-omnistudio-datamapper/assets/omni-data-transform-extract.json +6 -0
- package/skills/building-omnistudio-datamapper/assets/omni-data-transform-item.json +12 -0
- package/skills/building-omnistudio-datamapper/assets/omni-data-transform-load.json +6 -0
- package/skills/building-omnistudio-datamapper/assets/omni-data-transform-transform.json +6 -0
- package/skills/building-omnistudio-datamapper/references/best-practices.md +277 -0
- package/skills/building-omnistudio-datamapper/references/naming-conventions.md +145 -0
- package/skills/building-omnistudio-flexcard/CREDITS.md +5 -0
- package/skills/building-omnistudio-flexcard/SKILL.md +325 -0
- package/skills/building-omnistudio-flexcard/assets/omni-ui-card.json +10 -0
- package/skills/building-omnistudio-flexcard/references/best-practices.md +291 -0
- package/skills/building-omnistudio-flexcard/references/data-binding-guide.md +311 -0
- package/skills/building-omnistudio-flexcard/references/scoring-rubric.md +66 -0
- package/skills/building-omnistudio-flexcard/scripts/flexcard-commands.sh +24 -0
- package/skills/building-omnistudio-integration-procedure/CREDITS.md +5 -0
- package/skills/building-omnistudio-integration-procedure/SKILL.md +275 -0
- package/skills/building-omnistudio-integration-procedure/assets/omni-process-element-dr-extract.json +10 -0
- package/skills/building-omnistudio-integration-procedure/assets/omni-process-element-set-values.json +10 -0
- package/skills/building-omnistudio-integration-procedure/assets/omni-process-ip.json +12 -0
- package/skills/building-omnistudio-integration-procedure/assets/scoring-report-format.txt +14 -0
- package/skills/building-omnistudio-integration-procedure/references/best-practices.md +388 -0
- package/skills/building-omnistudio-integration-procedure/references/element-types.md +588 -0
- package/skills/building-omnistudio-integration-procedure/scripts/cli-commands.sh +18 -0
- package/skills/building-omnistudio-omniscript/CREDITS.md +5 -0
- package/skills/building-omnistudio-omniscript/SKILL.md +367 -0
- package/skills/building-omnistudio-omniscript/assets/omni-process-element-step.json +10 -0
- package/skills/building-omnistudio-omniscript/assets/omni-process-element-text-block.json +11 -0
- package/skills/building-omnistudio-omniscript/assets/omni-process-omniscript.json +12 -0
- package/skills/building-omnistudio-omniscript/references/best-practices.md +480 -0
- package/skills/building-omnistudio-omniscript/references/element-types.md +1172 -0
- package/skills/building-omnistudio-omniscript/scripts/check-duplicate-omniscript.sh +13 -0
- package/skills/building-omnistudio-omniscript/scripts/cli-reference.sh +21 -0
- package/skills/building-omnistudio-omniscript/scripts/deploy-omniscript.sh +29 -0
- package/skills/building-sf-integrations/CREDITS.md +5 -0
- package/skills/building-sf-integrations/README.md +95 -0
- package/skills/building-sf-integrations/SKILL.md +192 -0
- package/skills/building-sf-integrations/assets/callouts/callout-retry-handler.cls +167 -0
- package/skills/building-sf-integrations/assets/callouts/http-response-handler.cls +257 -0
- package/skills/building-sf-integrations/assets/callouts/rest-queueable-callout.cls +262 -0
- package/skills/building-sf-integrations/assets/callouts/rest-sync-callout.cls +211 -0
- package/skills/building-sf-integrations/assets/cdc/cdc-handler.cls +246 -0
- package/skills/building-sf-integrations/assets/cdc/cdc-subscriber-trigger.trigger +139 -0
- package/skills/building-sf-integrations/assets/endpoint-security/example.cspTrustedSite-meta.xml +58 -0
- package/skills/building-sf-integrations/assets/endpoint-security/example.remoteSite-meta.xml +39 -0
- package/skills/building-sf-integrations/assets/external-credentials/jwt-external-credential.externalCredential-meta.xml +90 -0
- package/skills/building-sf-integrations/assets/external-credentials/oauth-external-credential.externalCredential-meta.xml +87 -0
- package/skills/building-sf-integrations/assets/external-services/external-service-operations.md +221 -0
- package/skills/building-sf-integrations/assets/external-services/openapi-registration.externalServiceRegistration-meta.xml +193 -0
- package/skills/building-sf-integrations/assets/named-credentials/certificate-auth.namedCredential-meta.xml +62 -0
- package/skills/building-sf-integrations/assets/named-credentials/custom-auth.namedCredential-meta.xml +71 -0
- package/skills/building-sf-integrations/assets/named-credentials/oauth-client-credentials.namedCredential-meta.xml +51 -0
- package/skills/building-sf-integrations/assets/named-credentials/oauth-jwt-bearer.namedCredential-meta.xml +67 -0
- package/skills/building-sf-integrations/assets/platform-events/event-publisher.cls +191 -0
- package/skills/building-sf-integrations/assets/platform-events/event-subscriber-action.cls +295 -0
- package/skills/building-sf-integrations/assets/platform-events/event-subscriber-trigger.trigger +108 -0
- package/skills/building-sf-integrations/assets/platform-events/platform-event-definition.object-meta.xml +124 -0
- package/skills/building-sf-integrations/assets/soap/soap-callout-service.cls +186 -0
- package/skills/building-sf-integrations/assets/soap/wsdl2apex-guide.md +213 -0
- package/skills/building-sf-integrations/hooks/scripts/suggest_credential_setup.py +271 -0
- package/skills/building-sf-integrations/hooks/scripts/validate_integration.py +363 -0
- package/skills/building-sf-integrations/references/callout-patterns.md +719 -0
- package/skills/building-sf-integrations/references/cdc-guide.md +288 -0
- package/skills/building-sf-integrations/references/cli-reference.md +94 -0
- package/skills/building-sf-integrations/references/event-driven-architecture-guide.md +266 -0
- package/skills/building-sf-integrations/references/event-patterns.md +838 -0
- package/skills/building-sf-integrations/references/external-services-guide.md +303 -0
- package/skills/building-sf-integrations/references/messaging-api-v2.md +609 -0
- package/skills/building-sf-integrations/references/named-credentials-automation.md +201 -0
- package/skills/building-sf-integrations/references/named-credentials-guide.md +173 -0
- package/skills/building-sf-integrations/references/platform-events-guide.md +288 -0
- package/skills/building-sf-integrations/references/rest-callout-patterns.md +288 -0
- package/skills/building-sf-integrations/references/scoring-rubric.md +59 -0
- package/skills/building-sf-integrations/references/security-best-practices.md +248 -0
- package/skills/building-sf-integrations/scripts/README.md +100 -0
- package/skills/building-sf-integrations/scripts/configure-named-credential.sh +236 -0
- package/skills/building-sf-integrations/scripts/set-api-credential.sh +146 -0
- package/skills/building-sf-integrations/scripts/templates/setup-credentials-with-csp.sh +158 -0
- package/skills/building-ui-bundle-frontend/SKILL.md +2 -0
- package/skills/configuring-connected-apps/CREDITS.md +3 -0
- package/skills/configuring-connected-apps/README.md +99 -0
- package/skills/configuring-connected-apps/SKILL.md +224 -0
- package/skills/configuring-connected-apps/assets/connected-app-basic.xml +29 -0
- package/skills/configuring-connected-apps/assets/connected-app-canvas.xml +62 -0
- package/skills/configuring-connected-apps/assets/connected-app-jwt.xml +49 -0
- package/skills/configuring-connected-apps/assets/connected-app-oauth.xml +65 -0
- package/skills/configuring-connected-apps/assets/eca-global-oauth.xml +36 -0
- package/skills/configuring-connected-apps/assets/eca-oauth-settings.xml +36 -0
- package/skills/configuring-connected-apps/assets/eca-policies.xml +36 -0
- package/skills/configuring-connected-apps/assets/external-client-app.xml +35 -0
- package/skills/configuring-connected-apps/references/example-usage.md +256 -0
- package/skills/configuring-connected-apps/references/migration-guide.md +328 -0
- package/skills/configuring-connected-apps/references/oauth-flows-reference.md +660 -0
- package/skills/configuring-connected-apps/references/security-checklist.md +209 -0
- package/skills/configuring-connected-apps/references/testing-validation-guide.md +275 -0
- package/skills/connecting-datacloud/CREDITS.md +5 -0
- package/skills/connecting-datacloud/README.md +59 -0
- package/skills/connecting-datacloud/SKILL.md +155 -0
- package/skills/connecting-datacloud/examples/connections/heroku-postgres.json +15 -0
- package/skills/connecting-datacloud/examples/connections/ingest-api-connection.json +5 -0
- package/skills/connecting-datacloud/examples/connections/ingest-api-schema.json +31 -0
- package/skills/connecting-datacloud/examples/connections/redshift.json +16 -0
- package/skills/connecting-datacloud/examples/connections/sharepoint-unstructured.json +20 -0
- package/skills/connecting-datacloud/examples/connections/snowflake-connection.json +42 -0
- package/skills/debugging-apex-logs/CREDITS.md +22 -0
- package/skills/debugging-apex-logs/README.md +74 -0
- package/skills/debugging-apex-logs/SKILL.md +172 -0
- package/skills/debugging-apex-logs/assets/benchmarking-template.cls +327 -0
- package/skills/debugging-apex-logs/assets/cpu-heap-optimization.cls +307 -0
- package/skills/debugging-apex-logs/assets/dml-in-loop-fix.cls +219 -0
- package/skills/debugging-apex-logs/assets/null-pointer-fix.cls +252 -0
- package/skills/debugging-apex-logs/assets/soql-in-loop-fix.cls +157 -0
- package/skills/debugging-apex-logs/references/analysis-playbook.md +53 -0
- package/skills/debugging-apex-logs/references/benchmarking-guide.md +287 -0
- package/skills/debugging-apex-logs/references/cli-commands.md +368 -0
- package/skills/debugging-apex-logs/references/common-issues.md +68 -0
- package/skills/debugging-apex-logs/references/debug-log-reference.md +328 -0
- package/skills/debugging-apex-logs/references/log-analysis-tools.md +248 -0
- package/skills/debugging-apex-logs/references/scoring-rubric.md +21 -0
- package/skills/deploying-metadata/CREDITS.md +25 -0
- package/skills/deploying-metadata/README.md +104 -0
- package/skills/deploying-metadata/SKILL.md +214 -0
- package/skills/deploying-metadata/assets/destructiveChanges.xml +143 -0
- package/skills/deploying-metadata/assets/package.xml +121 -0
- package/skills/deploying-metadata/references/agent-deployment-guide.md +628 -0
- package/skills/deploying-metadata/references/deploy.sh +73 -0
- package/skills/deploying-metadata/references/deployment-report-template.md +89 -0
- package/skills/deploying-metadata/references/deployment-workflows.md +395 -0
- package/skills/deploying-metadata/references/orchestration.md +183 -0
- package/skills/deploying-metadata/references/trigger-deployment-safety.md +376 -0
- package/skills/deploying-omnistudio-datapacks/CREDITS.md +5 -0
- package/skills/deploying-omnistudio-datapacks/README.md +88 -0
- package/skills/deploying-omnistudio-datapacks/SKILL.md +174 -0
- package/skills/deploying-omnistudio-datapacks/examples/business-internet-plus-bundle/TRANSCRIPT.md +124 -0
- package/skills/deploying-omnistudio-datapacks/examples/business-internet-plus-bundle/deploy-business-internet-plus-bundle.yaml +11 -0
- package/skills/deploying-omnistudio-datapacks/examples/business-internet-plus-bundle-deploy/TRANSCRIPT.md +142 -0
- package/skills/deploying-omnistudio-datapacks/examples/business-internet-plus-bundle-deploy/deploy-business-internet-plus-bundle.yaml +10 -0
- package/skills/deploying-omnistudio-datapacks/references/job-file-template.md +42 -0
- package/skills/deploying-omnistudio-datapacks/references/troubleshooting-matrix.md +24 -0
- package/skills/deploying-ui-bundle/SKILL.md +2 -0
- package/skills/developing-agentforce/SKILL.md +1 -1
- package/skills/developing-agentforce/assets/metadata/http-callout-flow.flow-meta.xml +1 -1
- package/skills/developing-agentforce/references/actions-reference.md +8 -8
- package/skills/fetching-salesforce-docs/README.md +66 -0
- package/skills/fetching-salesforce-docs/SKILL.md +209 -0
- package/skills/fetching-salesforce-docs/requirements.txt +2 -0
- package/skills/fetching-salesforce-docs/scripts/extract_help_salesforce.py +497 -0
- package/skills/fetching-salesforce-docs/scripts/extract_salesforce_doc.py +357 -0
- package/skills/fetching-salesforce-docs/scripts/runtime_bootstrap.py +58 -0
- package/skills/generating-apex/CREDITS.md +1 -26
- package/skills/generating-apex/SKILL.md +4 -2
- package/skills/generating-apex-test/CREDITS.md +2 -27
- package/skills/generating-apex-test/SKILL.md +3 -1
- package/skills/generating-custom-application/SKILL.md +2 -0
- package/skills/generating-custom-field/SKILL.md +3 -1
- package/skills/generating-custom-lightning-type/SKILL.md +2 -0
- package/skills/generating-custom-object/SKILL.md +3 -1
- package/skills/generating-custom-tab/SKILL.md +3 -1
- package/skills/generating-flexipage/SKILL.md +2 -0
- package/skills/generating-flow/SKILL.md +2 -0
- package/skills/generating-lightning-app/SKILL.md +1 -1
- package/skills/generating-list-view/SKILL.md +2 -0
- package/skills/generating-lwc-components/CREDITS.md +5 -0
- package/skills/generating-lwc-components/README.md +126 -0
- package/skills/generating-lwc-components/SKILL.md +191 -0
- package/skills/generating-lwc-components/assets/apex-controller/LwcController.cls +327 -0
- package/skills/generating-lwc-components/assets/basic-component/basicComponent.css +72 -0
- package/skills/generating-lwc-components/assets/basic-component/basicComponent.html +111 -0
- package/skills/generating-lwc-components/assets/basic-component/basicComponent.js +163 -0
- package/skills/generating-lwc-components/assets/basic-component/basicComponent.js-meta.xml +137 -0
- package/skills/generating-lwc-components/assets/datatable-component/datatableComponent.html +111 -0
- package/skills/generating-lwc-components/assets/datatable-component/datatableComponent.js +367 -0
- package/skills/generating-lwc-components/assets/flow-screen-component/flowScreenComponent.css +63 -0
- package/skills/generating-lwc-components/assets/flow-screen-component/flowScreenComponent.html +154 -0
- package/skills/generating-lwc-components/assets/flow-screen-component/flowScreenComponent.js +348 -0
- package/skills/generating-lwc-components/assets/flow-screen-component/flowScreenComponent.js-meta.xml +87 -0
- package/skills/generating-lwc-components/assets/form-component/formComponent.html +165 -0
- package/skills/generating-lwc-components/assets/form-component/formComponent.js +275 -0
- package/skills/generating-lwc-components/assets/graphql-component/graphqlComponent.html +100 -0
- package/skills/generating-lwc-components/assets/graphql-component/graphqlComponent.js +336 -0
- package/skills/generating-lwc-components/assets/jest-test/componentName.test.js.example +371 -0
- package/skills/generating-lwc-components/assets/message-channel/RecordSelected.messageChannel-meta.xml +71 -0
- package/skills/generating-lwc-components/assets/message-channel/lmsPublisher.js +103 -0
- package/skills/generating-lwc-components/assets/message-channel/lmsSubscriber.js +181 -0
- package/skills/generating-lwc-components/assets/modal-component/modalComponent.html +85 -0
- package/skills/generating-lwc-components/assets/modal-component/modalComponent.js +199 -0
- package/skills/generating-lwc-components/assets/record-picker/recordPicker.html +55 -0
- package/skills/generating-lwc-components/assets/record-picker/recordPicker.js +199 -0
- package/skills/generating-lwc-components/assets/state-store/store.js +282 -0
- package/skills/generating-lwc-components/assets/typescript-component/typescriptComponent.css +65 -0
- package/skills/generating-lwc-components/assets/typescript-component/typescriptComponent.html +95 -0
- package/skills/generating-lwc-components/assets/typescript-component/typescriptComponent.js-meta.xml +75 -0
- package/skills/generating-lwc-components/assets/typescript-component/typescriptComponent.test.ts.example +301 -0
- package/skills/generating-lwc-components/assets/typescript-component/typescriptComponent.ts +295 -0
- package/skills/generating-lwc-components/assets/workspace-api/workspaceComponent.html +71 -0
- package/skills/generating-lwc-components/assets/workspace-api/workspaceComponent.js +316 -0
- package/skills/generating-lwc-components/hooks/scripts/lwc-lsp-validate.py +295 -0
- package/skills/generating-lwc-components/hooks/scripts/post-tool-validate.py +347 -0
- package/skills/generating-lwc-components/hooks/scripts/slds_data/deprecated_patterns.json +74 -0
- package/skills/generating-lwc-components/hooks/scripts/slds_data/styling_hooks.json +111 -0
- package/skills/generating-lwc-components/hooks/scripts/slds_data/valid_slds_classes.json +127 -0
- package/skills/generating-lwc-components/hooks/scripts/slds_linter_wrapper.py +294 -0
- package/skills/generating-lwc-components/hooks/scripts/slds_rules/__init__.py +22 -0
- package/skills/generating-lwc-components/hooks/scripts/template_validator.py +332 -0
- package/skills/generating-lwc-components/hooks/scripts/validate_slds.py +595 -0
- package/skills/generating-lwc-components/references/accessibility-guide.md +843 -0
- package/skills/generating-lwc-components/references/advanced-features.md +108 -0
- package/skills/generating-lwc-components/references/async-notification-patterns.md +661 -0
- package/skills/generating-lwc-components/references/cli-commands.md +545 -0
- package/skills/generating-lwc-components/references/component-patterns.md +1476 -0
- package/skills/generating-lwc-components/references/flow-integration-guide.md +675 -0
- package/skills/generating-lwc-components/references/jest-testing.md +1011 -0
- package/skills/generating-lwc-components/references/lms-guide.md +860 -0
- package/skills/generating-lwc-components/references/lwc-best-practices.md +1310 -0
- package/skills/generating-lwc-components/references/performance-guide.md +861 -0
- package/skills/generating-lwc-components/references/scoring-and-testing.md +116 -0
- package/skills/generating-lwc-components/references/slds-blueprints.json +14389 -0
- package/skills/generating-lwc-components/references/slds-design-guide.md +166 -0
- package/skills/generating-lwc-components/references/state-management.md +642 -0
- package/skills/generating-lwc-components/references/template-anti-patterns.md +948 -0
- package/skills/generating-lwc-components/references/triangle-pattern.md +365 -0
- package/skills/generating-lwc-components/scripts/local-dev-preview.sh +34 -0
- package/skills/generating-mermaid-diagrams/CREDITS.md +46 -0
- package/skills/generating-mermaid-diagrams/README.md +114 -0
- package/skills/generating-mermaid-diagrams/SKILL.md +218 -0
- package/skills/generating-mermaid-diagrams/assets/agentforce/agent-flow.md +313 -0
- package/skills/generating-mermaid-diagrams/assets/architecture/system-landscape.md +351 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/b2b-commerce-erd.md +317 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/campaigns-erd.md +195 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/consent-erd.md +262 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/files-erd.md +266 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/forecasting-erd.md +261 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/fsl-erd.md +332 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/party-model-erd.md +237 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/quote-order-erd.md +277 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/revenue-cloud-erd.md +343 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/sales-cloud-erd.md +192 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/salesforce-erd.md +209 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/scheduler-erd.md +276 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/service-cloud-erd.md +217 -0
- package/skills/generating-mermaid-diagrams/assets/datamodel/territory-management-erd.md +241 -0
- package/skills/generating-mermaid-diagrams/assets/integration/api-sequence.md +387 -0
- package/skills/generating-mermaid-diagrams/assets/oauth/authorization-code-pkce.md +197 -0
- package/skills/generating-mermaid-diagrams/assets/oauth/authorization-code.md +152 -0
- package/skills/generating-mermaid-diagrams/assets/oauth/client-credentials.md +233 -0
- package/skills/generating-mermaid-diagrams/assets/oauth/device-authorization.md +295 -0
- package/skills/generating-mermaid-diagrams/assets/oauth/jwt-bearer.md +256 -0
- package/skills/generating-mermaid-diagrams/assets/oauth/refresh-token.md +281 -0
- package/skills/generating-mermaid-diagrams/assets/oauth/user-agent-social-sign-on.md +281 -0
- package/skills/generating-mermaid-diagrams/assets/role-hierarchy/user-hierarchy.md +322 -0
- package/skills/generating-mermaid-diagrams/references/color-palette.md +464 -0
- package/skills/generating-mermaid-diagrams/references/diagram-conventions.md +313 -0
- package/skills/generating-mermaid-diagrams/references/erd-conventions.md +320 -0
- package/skills/generating-mermaid-diagrams/references/mermaid-reference.md +434 -0
- package/skills/generating-mermaid-diagrams/references/mermaid-styling.md +81 -0
- package/skills/generating-mermaid-diagrams/references/preview-guide.md +49 -0
- package/skills/generating-mermaid-diagrams/references/usage-examples.md +340 -0
- package/skills/generating-mermaid-diagrams/scripts/README.md +160 -0
- package/skills/generating-mermaid-diagrams/scripts/mermaid_preview.py +654 -0
- package/skills/generating-mermaid-diagrams/scripts/query-org-metadata.py +293 -0
- package/skills/generating-ui-bundle-features/SKILL.md +2 -0
- package/skills/generating-ui-bundle-metadata/SKILL.md +2 -0
- package/skills/generating-ui-bundle-site/SKILL.md +2 -0
- package/skills/generating-validation-rule/SKILL.md +2 -0
- package/skills/generating-visual-diagrams/CREDITS.md +80 -0
- package/skills/generating-visual-diagrams/README.md +83 -0
- package/skills/generating-visual-diagrams/SKILL.md +208 -0
- package/skills/generating-visual-diagrams/assets/architecture/integration-flow.md +55 -0
- package/skills/generating-visual-diagrams/assets/erd/core-objects.md +131 -0
- package/skills/generating-visual-diagrams/assets/erd/custom-objects.md +60 -0
- package/skills/generating-visual-diagrams/assets/lwc/dashboard-card.md +45 -0
- package/skills/generating-visual-diagrams/assets/lwc/data-table.md +57 -0
- package/skills/generating-visual-diagrams/assets/lwc/record-form.md +60 -0
- package/skills/generating-visual-diagrams/assets/review/apex-review.md +57 -0
- package/skills/generating-visual-diagrams/assets/review/lwc-review.md +48 -0
- package/skills/generating-visual-diagrams/references/architect-aesthetic-guide.md +257 -0
- package/skills/generating-visual-diagrams/references/examples-index.md +35 -0
- package/skills/generating-visual-diagrams/references/gemini-cli-setup.md +65 -0
- package/skills/generating-visual-diagrams/references/interview-questions.md +529 -0
- package/skills/generating-visual-diagrams/references/iteration-workflow.md +173 -0
- package/skills/generating-visual-diagrams/scripts/check-prerequisites.sh +101 -0
- package/skills/generating-visual-diagrams/scripts/generate_image.py +243 -0
- package/skills/handling-sf-data/CREDITS.md +5 -0
- package/skills/handling-sf-data/README.md +112 -0
- package/skills/handling-sf-data/SKILL.md +235 -0
- package/skills/handling-sf-data/assets/bulk/bulk-insert-10000.apex +293 -0
- package/skills/handling-sf-data/assets/bulk/bulk-insert-200.apex +208 -0
- package/skills/handling-sf-data/assets/bulk/bulk-insert-500.apex +219 -0
- package/skills/handling-sf-data/assets/bulk/bulk-upsert-external-id.apex +324 -0
- package/skills/handling-sf-data/assets/cleanup/delete-by-created-date.apex +319 -0
- package/skills/handling-sf-data/assets/cleanup/delete-by-name.apex +240 -0
- package/skills/handling-sf-data/assets/cleanup/delete-test-data.apex +311 -0
- package/skills/handling-sf-data/assets/cleanup/rollback-transaction.apex +266 -0
- package/skills/handling-sf-data/assets/csv/account-import.csv +11 -0
- package/skills/handling-sf-data/assets/csv/contact-import.csv +11 -0
- package/skills/handling-sf-data/assets/csv/custom-object-import.csv +11 -0
- package/skills/handling-sf-data/assets/csv/opportunity-import.csv +11 -0
- package/skills/handling-sf-data/assets/factories/account-factory.apex +165 -0
- package/skills/handling-sf-data/assets/factories/case-factory.apex +237 -0
- package/skills/handling-sf-data/assets/factories/contact-factory.apex +168 -0
- package/skills/handling-sf-data/assets/factories/custom-object-factory.apex +260 -0
- package/skills/handling-sf-data/assets/factories/event-factory.apex +275 -0
- package/skills/handling-sf-data/assets/factories/hierarchy-factory.apex +372 -0
- package/skills/handling-sf-data/assets/factories/lead-factory.apex +190 -0
- package/skills/handling-sf-data/assets/factories/opportunity-factory.apex +206 -0
- package/skills/handling-sf-data/assets/factories/task-factory.apex +246 -0
- package/skills/handling-sf-data/assets/factories/user-factory.apex +278 -0
- package/skills/handling-sf-data/assets/json/account-contact-tree.json +130 -0
- package/skills/handling-sf-data/assets/json/account-opportunity-tree.json +110 -0
- package/skills/handling-sf-data/assets/json/full-hierarchy-tree.json +188 -0
- package/skills/handling-sf-data/assets/soql/aggregate.soql +226 -0
- package/skills/handling-sf-data/assets/soql/child-to-parent.soql +162 -0
- package/skills/handling-sf-data/assets/soql/parent-to-child.soql +153 -0
- package/skills/handling-sf-data/assets/soql/polymorphic.soql +198 -0
- package/skills/handling-sf-data/assets/soql/subquery.soql +287 -0
- package/skills/handling-sf-data/references/anonymous-apex-guide.md +98 -0
- package/skills/handling-sf-data/references/bulk-operations-guide.md +94 -0
- package/skills/handling-sf-data/references/bulk-testing-example.md +194 -0
- package/skills/handling-sf-data/references/cleanup-rollback-example.md +322 -0
- package/skills/handling-sf-data/references/cleanup-rollback-guide.md +84 -0
- package/skills/handling-sf-data/references/crud-workflow-example.md +183 -0
- package/skills/handling-sf-data/references/governor-limits-reference.md +74 -0
- package/skills/handling-sf-data/references/orchestration.md +174 -0
- package/skills/handling-sf-data/references/relationship-query-examples.md +249 -0
- package/skills/handling-sf-data/references/sf-cli-data-commands.md +158 -0
- package/skills/handling-sf-data/references/soql-relationship-guide.md +84 -0
- package/skills/handling-sf-data/references/test-data-best-practices.md +104 -0
- package/skills/handling-sf-data/references/test-data-factory-usage.md +290 -0
- package/skills/handling-sf-data/references/test-data-patterns.md +98 -0
- package/skills/handling-sf-data/scripts/soql_validator.py +292 -0
- package/skills/handling-sf-data/scripts/validate_data_operation.py +379 -0
- package/skills/harmonizing-datacloud/CREDITS.md +3 -0
- package/skills/harmonizing-datacloud/README.md +31 -0
- package/skills/harmonizing-datacloud/SKILL.md +117 -0
- package/skills/implementing-ui-bundle-agentforce-conversation-client/SKILL.md +1 -1
- package/skills/implementing-ui-bundle-file-upload/SKILL.md +2 -0
- package/skills/modeling-omnistudio-epc-catalog/CREDITS.md +14 -0
- package/skills/modeling-omnistudio-epc-catalog/README.md +89 -0
- package/skills/modeling-omnistudio-epc-catalog/SKILL.md +395 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/attribute-assignment-template.json +402 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/compiled-attribute-overrides-template.json +43 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/completion-block-template.txt +8 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/decomposition-relationships-template.json +233 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_AttributeAssignments.json +514 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_CompiledAttributeOverrides.json +21 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_DataPack.json +649 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_DecompositionRelationships.json +200 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_ObjectFieldAttributes.json +138 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_OrchestrationScenarios.json +54 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_OverrideDefinitions.json +266 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_ParentKeys.json +23 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_PriceListEntries.json +54 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_PricebookEntries.json +35 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_ProductChildItems.json +34 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_RuleAssignments.json +21 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_AttributeAssignments.json +410 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_DataPack.json +535 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_DecompositionRelationships.json +35 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_ObjectFieldAttributes.json +138 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_OrchestrationScenarios.json +28 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_ParentKeys.json +23 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_PriceListEntries.json +220 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_PricebookEntries.json +35 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_ProductChildItems.json +414 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_AttributeAssignments.json +382 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_DataPack.json +565 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_DecompositionRelationships.json +35 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_ObjectFieldAttributes.json +104 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_OrchestrationScenarios.json +28 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_ParentKeys.json +13 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_PriceListEntries.json +106 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_PricebookEntries.json +35 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_ProductChildItems.json +72 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/static-ip-simple-offer/Static-IP_AttributeAssignments.json +142 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/static-ip-simple-offer/Static-IP_DataPack.json +377 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/static-ip-simple-offer/Static-IP_DecompositionRelationships.json +35 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/static-ip-simple-offer/Static-IP_ObjectFieldAttributes.json +36 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/static-ip-simple-offer/Static-IP_ParentKeys.json +8 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/static-ip-simple-offer/Static-IP_PriceListEntries.json +54 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/static-ip-simple-offer/Static-IP_PricebookEntries.json +35 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/examples/static-ip-simple-offer/Static-IP_ProductChildItems.json +34 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/object-field-attributes-template.json +138 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/orchestration-scenarios-template.json +54 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/override-definitions-template.json +134 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/parent-keys-template.json +29 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/price-list-entries-template.json +158 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/pricebook-entries-template.json +35 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/product-child-item-template.json +338 -0
- package/skills/modeling-omnistudio-epc-catalog/assets/product2-offer-template.json +527 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/.gitkeep +1 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_AttributeAssignments.json +95 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_CompiledAttributeOverrides.json +1 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_DataPack.json +214 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_DecompositionRelationships.json +28 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_ObjectFieldAttributes.json +98 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_OrchestrationScenarios.json +22 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_OverrideDefinitions.json +1 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_ParentKeys.json +13 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_PriceListEntries.json +35 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_PricebookEntries.json +28 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/Business-Internet-Plus_ProductChildItems.json +110 -0
- package/skills/modeling-omnistudio-epc-catalog/examples/business-internet-plus-bundle/TRANSCRIPT.md +58 -0
- package/skills/modeling-omnistudio-epc-catalog/references/epc-field-guide.md +90 -0
- package/skills/modeling-omnistudio-epc-catalog/references/naming-conventions.md +80 -0
- package/skills/modeling-omnistudio-epc-catalog/references/scoring-model.md +57 -0
- package/skills/modeling-omnistudio-epc-catalog/scripts/cli-validation-commands.sh +19 -0
- package/skills/modeling-omnistudio-epc-catalog/scripts/sample-invocations.sh +18 -0
- package/skills/observing-agentforce/SKILL.md +1 -1
- package/skills/orchestrating-datacloud/CREDITS.md +15 -0
- package/skills/orchestrating-datacloud/README.md +129 -0
- package/skills/orchestrating-datacloud/SKILL.md +236 -0
- package/skills/orchestrating-datacloud/UPSTREAM.md +45 -0
- package/skills/orchestrating-datacloud/assets/definitions/activation-target.template.json +5 -0
- package/skills/orchestrating-datacloud/assets/definitions/activation.template.json +7 -0
- package/skills/orchestrating-datacloud/assets/definitions/calculated-insight.template.json +7 -0
- package/skills/orchestrating-datacloud/assets/definitions/data-action-target.template.json +5 -0
- package/skills/orchestrating-datacloud/assets/definitions/data-action.template.json +5 -0
- package/skills/orchestrating-datacloud/assets/definitions/data-graph.template.json +21 -0
- package/skills/orchestrating-datacloud/assets/definitions/data-stream.template.json +55 -0
- package/skills/orchestrating-datacloud/assets/definitions/dmo.template.json +17 -0
- package/skills/orchestrating-datacloud/assets/definitions/identity-resolution.template.json +30 -0
- package/skills/orchestrating-datacloud/assets/definitions/mapping.template.json +14 -0
- package/skills/orchestrating-datacloud/assets/definitions/relationship.template.json +12 -0
- package/skills/orchestrating-datacloud/assets/definitions/search-index.template.json +9 -0
- package/skills/orchestrating-datacloud/assets/definitions/segment.template.json +16 -0
- package/skills/orchestrating-datacloud/references/feature-readiness.md +157 -0
- package/skills/orchestrating-datacloud/references/plugin-setup.md +140 -0
- package/skills/orchestrating-datacloud/scripts/bootstrap-plugin.sh +53 -0
- package/skills/orchestrating-datacloud/scripts/diagnose-org.mjs +511 -0
- package/skills/orchestrating-datacloud/scripts/generate-manifest.mjs +68 -0
- package/skills/orchestrating-datacloud/scripts/verify-plugin.sh +58 -0
- package/skills/preparing-datacloud/CREDITS.md +7 -0
- package/skills/preparing-datacloud/README.md +51 -0
- package/skills/preparing-datacloud/SKILL.md +191 -0
- package/skills/preparing-datacloud/examples/ingestion-api/.env.example +8 -0
- package/skills/preparing-datacloud/examples/ingestion-api/README.md +48 -0
- package/skills/preparing-datacloud/examples/ingestion-api/send-data.py +144 -0
- package/skills/querying-soql/CREDITS.md +21 -0
- package/skills/querying-soql/README.md +41 -0
- package/skills/querying-soql/SKILL.md +143 -0
- package/skills/querying-soql/assets/aggregate-queries.soql +242 -0
- package/skills/querying-soql/assets/basic-queries.soql +188 -0
- package/skills/querying-soql/assets/bulkified-query-pattern.cls +280 -0
- package/skills/querying-soql/assets/optimization-patterns.soql +259 -0
- package/skills/querying-soql/assets/relationship-queries.soql +203 -0
- package/skills/querying-soql/assets/selector-class.cls +219 -0
- package/skills/querying-soql/references/anti-patterns.md +348 -0
- package/skills/querying-soql/references/cli-commands.md +358 -0
- package/skills/querying-soql/references/field-coverage-rules.md +514 -0
- package/skills/querying-soql/references/query-optimization.md +142 -0
- package/skills/querying-soql/references/selector-patterns.md +479 -0
- package/skills/querying-soql/references/soql-reference.md +227 -0
- package/skills/querying-soql/references/soql-syntax-reference.md +208 -0
- package/skills/querying-soql/scripts/post-tool-validate.py +322 -0
- package/skills/retrieving-datacloud/CREDITS.md +7 -0
- package/skills/retrieving-datacloud/README.md +44 -0
- package/skills/retrieving-datacloud/SKILL.md +120 -0
- package/skills/retrieving-datacloud/examples/search-indexes/hybrid-structured.json +44 -0
- package/skills/retrieving-datacloud/examples/search-indexes/vector-knowledge.json +43 -0
- package/skills/running-apex-tests/CREDITS.md +22 -0
- package/skills/running-apex-tests/README.md +94 -0
- package/skills/running-apex-tests/SKILL.md +158 -0
- package/skills/running-apex-tests/assets/basic-test.cls +169 -0
- package/skills/running-apex-tests/assets/bulk-test.cls +255 -0
- package/skills/running-apex-tests/assets/dml-mock.cls +339 -0
- package/skills/running-apex-tests/assets/mock-callout-test.cls +353 -0
- package/skills/running-apex-tests/assets/stub-provider-example.cls +364 -0
- package/skills/running-apex-tests/assets/test-data-factory.cls +328 -0
- package/skills/running-apex-tests/hooks/scripts/parse-test-results.py +364 -0
- package/skills/running-apex-tests/references/cli-commands.md +289 -0
- package/skills/running-apex-tests/references/mocking-patterns.md +500 -0
- package/skills/running-apex-tests/references/performance-optimization.md +283 -0
- package/skills/running-apex-tests/references/test-fix-loop.md +49 -0
- package/skills/running-apex-tests/references/test-patterns.md +154 -0
- package/skills/running-apex-tests/references/testing-best-practices.md +509 -0
- package/skills/segmenting-datacloud/CREDITS.md +3 -0
- package/skills/segmenting-datacloud/README.md +36 -0
- package/skills/segmenting-datacloud/SKILL.md +115 -0
- package/skills/switching-org/SKILL.md +1 -1
- package/skills/testing-agentforce/SKILL.md +1 -1
- package/skills/uplifting-components-to-slds2/SKILL.md +3 -1
- package/skills/using-ui-bundle-salesforce-data/SKILL.md +2 -0
|
@@ -0,0 +1,1310 @@
|
|
|
1
|
+
<!-- Parent: generating-lwc-components/SKILL.md -->
|
|
2
|
+
# Lightning Web Components Best Practices
|
|
3
|
+
|
|
4
|
+
This guide provides comprehensive best practices for building production-ready LWC components, organized around the **PICKLES Framework** and incorporating advanced patterns from industry experts.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## PICKLES Framework Overview
|
|
9
|
+
|
|
10
|
+
The PICKLES Framework provides a structured approach to LWC architecture. Use it as a checklist during component design and implementation.
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
🥒 P - Prototype → Validate ideas with wireframes & mock data
|
|
14
|
+
🥒 I - Integrate → Choose data source (LDS, Apex, GraphQL)
|
|
15
|
+
🥒 C - Composition → Structure component hierarchy & communication
|
|
16
|
+
🥒 K - Kinetics → Handle user interactions & event flow
|
|
17
|
+
🥒 L - Libraries → Leverage platform APIs & base components
|
|
18
|
+
🥒 E - Execution → Optimize performance & lifecycle hooks
|
|
19
|
+
🥒 S - Security → Enforce permissions & data protection
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Reference**: [PICKLES Framework](https://www.salesforceben.com/the-ideal-framework-for-architecting-salesforce-lightning-web-components/) — David Picksley, Third Eye Consulting
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Component Design Principles
|
|
27
|
+
|
|
28
|
+
### Single Responsibility (PICKLES: Composition)
|
|
29
|
+
|
|
30
|
+
Each component should do one thing well.
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
✅ GOOD: accountCard, accountList, accountForm (separate components)
|
|
34
|
+
❌ BAD: accountManager (does display, list, and form in one)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Composition Over Inheritance
|
|
38
|
+
|
|
39
|
+
Build complex UIs by composing simple components.
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<!-- Compose components -->
|
|
43
|
+
<template>
|
|
44
|
+
<c-page-header title="Accounts"></c-page-header>
|
|
45
|
+
<c-account-filters onfilter={handleFilter}></c-account-filters>
|
|
46
|
+
<c-account-list accounts={filteredAccounts}></c-account-list>
|
|
47
|
+
<c-pagination total={totalCount} onpage={handlePage}></c-pagination>
|
|
48
|
+
</template>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Unidirectional Data Flow
|
|
52
|
+
|
|
53
|
+
Data flows down (props), events bubble up.
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
57
|
+
│ DATA FLOW PATTERN │
|
|
58
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
59
|
+
│ │
|
|
60
|
+
│ Parent Component │
|
|
61
|
+
│ ┌─────────────────────────────────────────────────────────┐ │
|
|
62
|
+
│ │ state: accounts = [...] │ │
|
|
63
|
+
│ │ │ │
|
|
64
|
+
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
|
|
65
|
+
│ │ │ Child A │ ←── │ Child B │ ←── │ Child C │ │ │
|
|
66
|
+
│ │ │ │ │ │ │ │ │ │
|
|
67
|
+
│ │ │ @api │ │ @api │ │ @api │ │ │
|
|
68
|
+
│ │ │ accounts │ │ selected │ │ details │ │ │
|
|
69
|
+
│ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │
|
|
70
|
+
│ │ │ │ │ │ │
|
|
71
|
+
│ │ │ Events │ Events │ Events │ │
|
|
72
|
+
│ │ └────────────────┴────────────────┘ │ │
|
|
73
|
+
│ │ ↑ bubbles to parent │ │
|
|
74
|
+
│ └─────────────────────────────────────────────────────────┘ │
|
|
75
|
+
│ │
|
|
76
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Naming & Decorator Conventions
|
|
82
|
+
|
|
83
|
+
### Property & Attribute Naming
|
|
84
|
+
|
|
85
|
+
| Context | Convention | Example |
|
|
86
|
+
|---------|-----------|---------|
|
|
87
|
+
| JavaScript properties | camelCase | `itemName`, `maxValue` |
|
|
88
|
+
| HTML attributes | kebab-case, lowercase | `item-name`, `max-value` |
|
|
89
|
+
| Dispatched event names | Lowercase, no `on` prefix | `'recordchange'`, `'save'` |
|
|
90
|
+
| HTML event listeners | `on` + event name | `onrecordchange`, `onsave` |
|
|
91
|
+
|
|
92
|
+
Reserved prefixes in JS property names: `on`, `aria`, `data`. Reserved words: `slot`, `part`, `is`.
|
|
93
|
+
|
|
94
|
+
### @api Decorator Rules
|
|
95
|
+
|
|
96
|
+
- Only one decorator per field/method — do not combine `@api` with `@track` or `@wire`
|
|
97
|
+
- For getter/setter pairs: decorate only the getter, and always define both getter and setter
|
|
98
|
+
- Never mutate `@api` properties internally — use a private reactive copy instead
|
|
99
|
+
- Only use `@api` on properties/methods that are part of the component's public API
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
// ✅ GOOD: getter/setter with @api on getter only
|
|
103
|
+
_recordId;
|
|
104
|
+
|
|
105
|
+
@api
|
|
106
|
+
get recordId() { return this._recordId; }
|
|
107
|
+
set recordId(value) {
|
|
108
|
+
this._recordId = value;
|
|
109
|
+
this.loadRecord();
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### @track Decorator Rules
|
|
114
|
+
|
|
115
|
+
Since Spring '20, primitive properties are reactive by default. `@track` is only needed when **mutating nested properties** of objects or arrays.
|
|
116
|
+
|
|
117
|
+
| Scenario | @track Needed? |
|
|
118
|
+
|----------|----------------|
|
|
119
|
+
| Primitive value (`string`, `number`, `boolean`) | No |
|
|
120
|
+
| Object/array that is **reassigned** entirely | No |
|
|
121
|
+
| Object with **nested property mutation** (`this.obj.nested.value++`) | Yes |
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
// ❌ Unnecessary: primitives are reactive by default
|
|
125
|
+
@track searchTerm = '';
|
|
126
|
+
|
|
127
|
+
// ✅ Correct: remove @track for primitives
|
|
128
|
+
searchTerm = '';
|
|
129
|
+
|
|
130
|
+
// ✅ Correct: @track needed for nested mutation
|
|
131
|
+
@track formData = { billing: { city: '' } };
|
|
132
|
+
// later: this.formData.billing.city = 'San Francisco';
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Data Integration (PICKLES: Integrate)
|
|
138
|
+
|
|
139
|
+
### Data Source Decision Tree
|
|
140
|
+
|
|
141
|
+
| Scenario | Recommended Approach |
|
|
142
|
+
|----------|---------------------|
|
|
143
|
+
| Single record by ID | Lightning Data Service (`getRecord`) |
|
|
144
|
+
| Simple record CRUD | `lightning-record-form` / `lightning-record-edit-form` |
|
|
145
|
+
| Complex queries | Apex with `@AuraEnabled(cacheable=true)` |
|
|
146
|
+
| Related records, filtering | GraphQL wire adapter |
|
|
147
|
+
| Real-time updates | Platform Events / Streaming API |
|
|
148
|
+
| External data | Named Credentials + Apex callout |
|
|
149
|
+
|
|
150
|
+
### GraphQL vs Apex Decision
|
|
151
|
+
|
|
152
|
+
| Use GraphQL When | Use Apex When |
|
|
153
|
+
|------------------|---------------|
|
|
154
|
+
| Fetching related objects | Complex business logic |
|
|
155
|
+
| Client-side filtering | Aggregate queries (COUNT, SUM) |
|
|
156
|
+
| Cursor-based pagination | Bulk DML operations |
|
|
157
|
+
| Reducing over-fetching | Callouts to external systems |
|
|
158
|
+
|
|
159
|
+
### Wire Service Best Practices
|
|
160
|
+
|
|
161
|
+
```javascript
|
|
162
|
+
// Store wire result for refreshApex
|
|
163
|
+
wiredAccountsResult;
|
|
164
|
+
|
|
165
|
+
@wire(getAccounts, { searchTerm: '$searchTerm' })
|
|
166
|
+
wiredAccounts(result) {
|
|
167
|
+
this.wiredAccountsResult = result; // Store for refresh
|
|
168
|
+
const { data, error } = result;
|
|
169
|
+
if (data) {
|
|
170
|
+
this.accounts = data;
|
|
171
|
+
this.error = undefined;
|
|
172
|
+
} else if (error) {
|
|
173
|
+
this.error = this.reduceErrors(error);
|
|
174
|
+
this.accounts = [];
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Refresh when needed
|
|
179
|
+
async handleRefresh() {
|
|
180
|
+
await refreshApex(this.wiredAccountsResult);
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Error Handling Pattern
|
|
185
|
+
|
|
186
|
+
```javascript
|
|
187
|
+
// Centralized error reducer
|
|
188
|
+
reduceErrors(errors) {
|
|
189
|
+
if (!Array.isArray(errors)) {
|
|
190
|
+
errors = [errors];
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return errors
|
|
194
|
+
.filter(error => !!error)
|
|
195
|
+
.map(error => {
|
|
196
|
+
// UI API errors
|
|
197
|
+
if (error.body?.message) return error.body.message;
|
|
198
|
+
// JS errors
|
|
199
|
+
if (error.message) return error.message;
|
|
200
|
+
// GraphQL errors
|
|
201
|
+
if (error.graphQLErrors) {
|
|
202
|
+
return error.graphQLErrors.map(e => e.message).join(', ');
|
|
203
|
+
}
|
|
204
|
+
return JSON.stringify(error);
|
|
205
|
+
})
|
|
206
|
+
.join('; ');
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Event Patterns (PICKLES: Kinetics)
|
|
212
|
+
|
|
213
|
+
### Custom Events
|
|
214
|
+
|
|
215
|
+
```javascript
|
|
216
|
+
// Child dispatches event
|
|
217
|
+
this.dispatchEvent(new CustomEvent('select', {
|
|
218
|
+
detail: { recordId: this.recordId },
|
|
219
|
+
bubbles: true, // Bubbles through DOM
|
|
220
|
+
composed: true // Crosses shadow boundary
|
|
221
|
+
}));
|
|
222
|
+
|
|
223
|
+
// Parent handles event
|
|
224
|
+
handleSelect(event) {
|
|
225
|
+
const recordId = event.detail.recordId;
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Event Bubbling Configuration
|
|
230
|
+
|
|
231
|
+
Choose the minimum propagation scope needed:
|
|
232
|
+
|
|
233
|
+
| Configuration | Encapsulation | Use Case |
|
|
234
|
+
|---------------|---------------|----------|
|
|
235
|
+
| `{ bubbles: false, composed: false }` | **Maximum** (Preferred) | Direct parent-child communication |
|
|
236
|
+
| `{ bubbles: true, composed: false }` | Acceptable | Internal shadow DOM communication |
|
|
237
|
+
| `{ bubbles: false, composed: true }` | Acceptable | Cross shadow boundary without full bubbling |
|
|
238
|
+
| `{ bubbles: true, composed: true }` | **Discouraged** | Only when grandparent+ must handle event |
|
|
239
|
+
|
|
240
|
+
```javascript
|
|
241
|
+
// ✅ Preferred: Maximum encapsulation
|
|
242
|
+
this.dispatchEvent(new CustomEvent('select', {
|
|
243
|
+
detail: { recordId: this.recordId }
|
|
244
|
+
// bubbles and composed default to false
|
|
245
|
+
}));
|
|
246
|
+
|
|
247
|
+
// ⚠️ Use only when necessary
|
|
248
|
+
this.dispatchEvent(new CustomEvent('globalnotify', {
|
|
249
|
+
detail: { message: 'Record saved' },
|
|
250
|
+
bubbles: true,
|
|
251
|
+
composed: true
|
|
252
|
+
}));
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Event Data Passing
|
|
256
|
+
|
|
257
|
+
```javascript
|
|
258
|
+
// Primitives: pass directly in detail
|
|
259
|
+
this.dispatchEvent(new CustomEvent('update', {
|
|
260
|
+
detail: this.recordId // string — no wrapping needed
|
|
261
|
+
}));
|
|
262
|
+
|
|
263
|
+
// Non-primitives: always pass a copy to prevent mutation
|
|
264
|
+
this.dispatchEvent(new CustomEvent('change', {
|
|
265
|
+
detail: { ...this.formData } // shallow copy
|
|
266
|
+
}));
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Event Naming Conventions
|
|
270
|
+
|
|
271
|
+
```
|
|
272
|
+
✅ GOOD ❌ BAD
|
|
273
|
+
──────────────────────── ────────────────────────
|
|
274
|
+
onselect onSelectItem
|
|
275
|
+
onrecordchange on-record-change
|
|
276
|
+
onsave onSaveClicked
|
|
277
|
+
onerror onErrorOccurred
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### When to Use LMS vs Events
|
|
281
|
+
|
|
282
|
+
| Scenario | Use |
|
|
283
|
+
|----------|-----|
|
|
284
|
+
| Parent-child communication | Custom events |
|
|
285
|
+
| Sibling components (same parent) | Events via parent |
|
|
286
|
+
| Components on different parts of page | Lightning Message Service |
|
|
287
|
+
| LWC to Aura communication | LMS |
|
|
288
|
+
| LWC to Visualforce | LMS |
|
|
289
|
+
|
|
290
|
+
### Debouncing Pattern
|
|
291
|
+
|
|
292
|
+
```javascript
|
|
293
|
+
delayTimeout;
|
|
294
|
+
|
|
295
|
+
handleSearch(event) {
|
|
296
|
+
const searchTerm = event.target.value;
|
|
297
|
+
clearTimeout(this.delayTimeout);
|
|
298
|
+
|
|
299
|
+
this.delayTimeout = setTimeout(() => {
|
|
300
|
+
this.searchTerm = searchTerm;
|
|
301
|
+
}, 300); // 300ms debounce
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## Spread Patterns & Destructuring
|
|
308
|
+
|
|
309
|
+
### lwc:spread Directive
|
|
310
|
+
|
|
311
|
+
The `lwc:spread` directive dynamically spreads object properties as component attributes. Useful for reducing boilerplate and enabling dynamic attribute binding.
|
|
312
|
+
|
|
313
|
+
**Reference**: [Saurabh Samir - lwc:spread Directive](https://medium.com/@saurabh.samirs)
|
|
314
|
+
|
|
315
|
+
#### Basic Usage
|
|
316
|
+
|
|
317
|
+
```html
|
|
318
|
+
<!-- Without lwc:spread (verbose) -->
|
|
319
|
+
<lightning-button
|
|
320
|
+
label={buttonLabel}
|
|
321
|
+
variant={buttonVariant}
|
|
322
|
+
disabled={isDisabled}
|
|
323
|
+
onclick={handleClick}>
|
|
324
|
+
</lightning-button>
|
|
325
|
+
|
|
326
|
+
<!-- With lwc:spread (dynamic) -->
|
|
327
|
+
<lightning-button lwc:spread={buttonAttributes} onclick={handleClick}></lightning-button>
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
```javascript
|
|
331
|
+
get buttonAttributes() {
|
|
332
|
+
return {
|
|
333
|
+
label: this.buttonLabel,
|
|
334
|
+
variant: this.isImportant ? 'brand' : 'neutral',
|
|
335
|
+
disabled: this.isProcessing
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
#### lwc:spread vs @api Object Binding
|
|
341
|
+
|
|
342
|
+
| Approach | Use When | Reactivity |
|
|
343
|
+
|----------|----------|------------|
|
|
344
|
+
| `lwc:spread={obj}` | Passing multiple attributes dynamically | Re-renders on object change |
|
|
345
|
+
| `@api config` | Passing structured data to custom component | Must spread in child |
|
|
346
|
+
| Individual `@api` props | Simple, known properties | Each prop triggers render |
|
|
347
|
+
|
|
348
|
+
#### Conditional Attribute Spreading
|
|
349
|
+
|
|
350
|
+
```javascript
|
|
351
|
+
get inputAttributes() {
|
|
352
|
+
const attrs = {
|
|
353
|
+
label: 'Search',
|
|
354
|
+
type: 'text',
|
|
355
|
+
value: this.searchTerm
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
// Conditionally add attributes
|
|
359
|
+
if (this.isRequired) {
|
|
360
|
+
attrs.required = true;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (this.maxLength) {
|
|
364
|
+
attrs['max-length'] = this.maxLength;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return attrs;
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
```html
|
|
372
|
+
<lightning-input lwc:spread={inputAttributes} onchange={handleChange}></lightning-input>
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
#### Event Handlers with lwc:spread
|
|
376
|
+
|
|
377
|
+
**Important**: Event handlers must be bound separately, not spread:
|
|
378
|
+
|
|
379
|
+
```html
|
|
380
|
+
<!-- ✅ CORRECT: Event handler separate from spread -->
|
|
381
|
+
<lightning-button lwc:spread={buttonProps} onclick={handleClick}></lightning-button>
|
|
382
|
+
|
|
383
|
+
<!-- ❌ INCORRECT: onclick in spread object won't work -->
|
|
384
|
+
<!-- buttonProps = { label: 'Save', onclick: this.handleClick } -->
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### lwc:on Directive (Spring '26 - API 66.0)
|
|
388
|
+
|
|
389
|
+
The `lwc:on` directive solves the limitation above by enabling **dynamic event binding** directly from JavaScript. It allows you to bind multiple event handlers at runtime.
|
|
390
|
+
|
|
391
|
+
**Requires**: API 66.0+ (Spring '26)
|
|
392
|
+
|
|
393
|
+
#### Basic Usage
|
|
394
|
+
|
|
395
|
+
```javascript
|
|
396
|
+
// component.js
|
|
397
|
+
export default class DynamicEventComponent extends LightningElement {
|
|
398
|
+
// Define event handlers as object properties
|
|
399
|
+
eventHandlers = {
|
|
400
|
+
click: this.handleClick.bind(this),
|
|
401
|
+
mouseover: this.handleMouseOver.bind(this),
|
|
402
|
+
focus: this.handleFocus.bind(this)
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
handleClick() {
|
|
406
|
+
console.log('Element clicked!');
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
handleMouseOver() {
|
|
410
|
+
console.log('Mouse over!');
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
handleFocus() {
|
|
414
|
+
console.log('Element focused!');
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
```html
|
|
420
|
+
<!-- template.html -->
|
|
421
|
+
<template>
|
|
422
|
+
<!-- Bind multiple event handlers dynamically -->
|
|
423
|
+
<button lwc:on={eventHandlers}>Click Me</button>
|
|
424
|
+
</template>
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
#### Combining lwc:spread and lwc:on
|
|
428
|
+
|
|
429
|
+
For fully dynamic components, combine both directives:
|
|
430
|
+
|
|
431
|
+
```javascript
|
|
432
|
+
// component.js
|
|
433
|
+
export default class FullyDynamicButton extends LightningElement {
|
|
434
|
+
// Properties via lwc:spread
|
|
435
|
+
buttonAttributes = {
|
|
436
|
+
label: 'Save',
|
|
437
|
+
variant: 'brand',
|
|
438
|
+
disabled: false
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
// Events via lwc:on
|
|
442
|
+
buttonEvents = {
|
|
443
|
+
click: this.handleClick.bind(this),
|
|
444
|
+
focus: this.handleFocus.bind(this)
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
handleClick() {
|
|
448
|
+
this.dispatchEvent(new CustomEvent('save'));
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
handleFocus() {
|
|
452
|
+
console.log('Button focused');
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
```html
|
|
458
|
+
<!-- template.html -->
|
|
459
|
+
<template>
|
|
460
|
+
<!-- Best of both worlds: dynamic props AND dynamic events -->
|
|
461
|
+
<lightning-button
|
|
462
|
+
lwc:spread={buttonAttributes}
|
|
463
|
+
lwc:on={buttonEvents}>
|
|
464
|
+
</lightning-button>
|
|
465
|
+
</template>
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
#### Dynamic Event Handlers from @api
|
|
469
|
+
|
|
470
|
+
Pass event handler configurations from parent components:
|
|
471
|
+
|
|
472
|
+
```javascript
|
|
473
|
+
// childComponent.js
|
|
474
|
+
export default class ChildComponent extends LightningElement {
|
|
475
|
+
@api eventConfig; // { click: handler, change: handler }
|
|
476
|
+
|
|
477
|
+
get resolvedHandlers() {
|
|
478
|
+
// Ensure handlers are properly bound
|
|
479
|
+
const handlers = {};
|
|
480
|
+
if (this.eventConfig) {
|
|
481
|
+
Object.entries(this.eventConfig).forEach(([event, handler]) => {
|
|
482
|
+
handlers[event] = typeof handler === 'function' ? handler : () => {};
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
return handlers;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
```html
|
|
491
|
+
<!-- childComponent.html -->
|
|
492
|
+
<template>
|
|
493
|
+
<div lwc:on={resolvedHandlers}>
|
|
494
|
+
<slot></slot>
|
|
495
|
+
</div>
|
|
496
|
+
</template>
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
#### Removing Event Listeners
|
|
500
|
+
|
|
501
|
+
Remove specific event listeners by omitting them from the object:
|
|
502
|
+
|
|
503
|
+
```javascript
|
|
504
|
+
// Toggle mouseover handler on/off
|
|
505
|
+
toggleHoverHandler() {
|
|
506
|
+
if (this._hoverEnabled) {
|
|
507
|
+
// Remove mouseover by omitting it
|
|
508
|
+
this.eventHandlers = {
|
|
509
|
+
click: this.handleClick.bind(this)
|
|
510
|
+
};
|
|
511
|
+
} else {
|
|
512
|
+
// Add mouseover back
|
|
513
|
+
this.eventHandlers = {
|
|
514
|
+
click: this.handleClick.bind(this),
|
|
515
|
+
mouseover: this.handleMouseOver.bind(this)
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
this._hoverEnabled = !this._hoverEnabled;
|
|
519
|
+
}
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
#### lwc:spread vs lwc:on Comparison
|
|
523
|
+
|
|
524
|
+
| Directive | Purpose | Use Case |
|
|
525
|
+
|-----------|---------|----------|
|
|
526
|
+
| `lwc:spread` | Dynamic **properties/attributes** | Pass label, variant, disabled dynamically |
|
|
527
|
+
| `lwc:on` | Dynamic **event handlers** | Bind click, change, custom events dynamically |
|
|
528
|
+
| Both together | Fully dynamic configuration | Reusable wrapper components, dynamic UIs |
|
|
529
|
+
|
|
530
|
+
**Important Notes**:
|
|
531
|
+
- Do NOT mutate the object passed to `lwc:on` - create a new object to update handlers
|
|
532
|
+
- Event type names should be lowercase without the `on` prefix (use `click` not `onclick`)
|
|
533
|
+
- Always use `.bind(this)` or arrow functions to preserve context
|
|
534
|
+
|
|
535
|
+
### Object Spread & Destructuring
|
|
536
|
+
|
|
537
|
+
Modern JavaScript patterns for cleaner data handling in LWC.
|
|
538
|
+
|
|
539
|
+
#### Object Spread for Config Merging
|
|
540
|
+
|
|
541
|
+
```javascript
|
|
542
|
+
// Default + user config pattern
|
|
543
|
+
const defaultConfig = {
|
|
544
|
+
pageSize: 10,
|
|
545
|
+
sortField: 'Name',
|
|
546
|
+
sortDirection: 'ASC'
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
get tableConfig() {
|
|
550
|
+
return {
|
|
551
|
+
...defaultConfig,
|
|
552
|
+
...this.userConfig // User config overrides defaults
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
#### Destructuring with Defaults
|
|
558
|
+
|
|
559
|
+
```javascript
|
|
560
|
+
// Extract values with fallbacks
|
|
561
|
+
handleRecordLoad(record) {
|
|
562
|
+
const {
|
|
563
|
+
Name = 'Unknown',
|
|
564
|
+
Industry = 'Not Specified',
|
|
565
|
+
AnnualRevenue = 0
|
|
566
|
+
} = record.fields;
|
|
567
|
+
|
|
568
|
+
this.accountName = Name.value;
|
|
569
|
+
this.industry = Industry.value;
|
|
570
|
+
this.revenue = AnnualRevenue.value;
|
|
571
|
+
}
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
#### Nested Destructuring
|
|
575
|
+
|
|
576
|
+
```javascript
|
|
577
|
+
// Deep extraction in single statement
|
|
578
|
+
processResult(result) {
|
|
579
|
+
const {
|
|
580
|
+
data: {
|
|
581
|
+
record: {
|
|
582
|
+
fields: { Name, BillingCity }
|
|
583
|
+
}
|
|
584
|
+
},
|
|
585
|
+
error
|
|
586
|
+
} = result;
|
|
587
|
+
|
|
588
|
+
if (error) {
|
|
589
|
+
this.handleError(error);
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
this.name = Name.value;
|
|
594
|
+
this.city = BillingCity.value;
|
|
595
|
+
}
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
#### Array Spread Patterns
|
|
599
|
+
|
|
600
|
+
```javascript
|
|
601
|
+
// Immutable array updates (required for LWC reactivity)
|
|
602
|
+
addItem(newItem) {
|
|
603
|
+
this.items = [...this.items, newItem]; // Append
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
removeItem(index) {
|
|
607
|
+
this.items = [
|
|
608
|
+
...this.items.slice(0, index),
|
|
609
|
+
...this.items.slice(index + 1)
|
|
610
|
+
]; // Remove at index
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
updateItem(index, updates) {
|
|
614
|
+
this.items = this.items.map((item, i) =>
|
|
615
|
+
i === index ? { ...item, ...updates } : item
|
|
616
|
+
); // Update at index
|
|
617
|
+
}
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
#### Parameter Spreading in Apex Calls
|
|
621
|
+
|
|
622
|
+
```javascript
|
|
623
|
+
async handleSubmit() {
|
|
624
|
+
const result = await createRecord({
|
|
625
|
+
...this.recordData,
|
|
626
|
+
CreatedBy__c: this.currentUserId,
|
|
627
|
+
Status__c: 'Pending'
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
### When to Use Each Pattern
|
|
633
|
+
|
|
634
|
+
| Pattern | Best For | Avoid When |
|
|
635
|
+
|---------|----------|------------|
|
|
636
|
+
| `lwc:spread` | Many dynamic attributes, base component wrappers | Need event binding, simple static props |
|
|
637
|
+
| Object spread | Config merging, immutable updates | Deep objects (consider structuredClone) |
|
|
638
|
+
| Destructuring | Extracting multiple values, API responses | Simple single-property access |
|
|
639
|
+
| Array spread | Adding/removing items immutably | Large arrays (performance concern) |
|
|
640
|
+
|
|
641
|
+
---
|
|
642
|
+
|
|
643
|
+
## Complex Template Expressions (Spring '26 Beta - API 66.0)
|
|
644
|
+
|
|
645
|
+
Spring '26 introduces **complex template expressions**, enabling JavaScript expressions directly in templates. This was previously limited to simple property and getter bindings.
|
|
646
|
+
|
|
647
|
+
> ⚠️ **Beta Feature**: Use getters in production until this becomes GA. Document any complex expressions for future migration.
|
|
648
|
+
|
|
649
|
+
### Before vs After
|
|
650
|
+
|
|
651
|
+
```html
|
|
652
|
+
<!-- BEFORE Spring '26: Required getters for any logic -->
|
|
653
|
+
<template>
|
|
654
|
+
<!-- Simple property binding only -->
|
|
655
|
+
<template lwc:if={isValid}>...</template>
|
|
656
|
+
|
|
657
|
+
<!-- Complex conditions needed a getter -->
|
|
658
|
+
<template lwc:if={showLoadingState}>...</template>
|
|
659
|
+
</template>
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
```javascript
|
|
663
|
+
// Required getter in JS
|
|
664
|
+
get showLoadingState() {
|
|
665
|
+
return this.isLoading && this.items.length === 0;
|
|
666
|
+
}
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
```html
|
|
670
|
+
<!-- AFTER Spring '26 (Beta): Complex expressions in template -->
|
|
671
|
+
<template>
|
|
672
|
+
<!-- Logical operators -->
|
|
673
|
+
<template lwc:if={!isLoading && items.length > 0}>
|
|
674
|
+
<c-item-list items={items}></c-item-list>
|
|
675
|
+
</template>
|
|
676
|
+
|
|
677
|
+
<!-- Optional chaining -->
|
|
678
|
+
<template lwc:if={user?.permissions?.canEdit}>
|
|
679
|
+
<lightning-button label="Edit"></lightning-button>
|
|
680
|
+
</template>
|
|
681
|
+
|
|
682
|
+
<!-- Arithmetic expressions -->
|
|
683
|
+
<span class="slds-text-body_small">
|
|
684
|
+
Total: ${total * taxRate}
|
|
685
|
+
</span>
|
|
686
|
+
|
|
687
|
+
<!-- Comparison operators -->
|
|
688
|
+
<template lwc:if={items.length >= minItems}>
|
|
689
|
+
<c-pagination></c-pagination>
|
|
690
|
+
</template>
|
|
691
|
+
</template>
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
### Supported Expression Types
|
|
695
|
+
|
|
696
|
+
| Expression Type | Example | Notes |
|
|
697
|
+
|-----------------|---------|-------|
|
|
698
|
+
| **Logical NOT** | `{!isLoading}` | Negation |
|
|
699
|
+
| **Logical AND** | `{a && b}` | Short-circuit evaluation |
|
|
700
|
+
| **Logical OR** | `{a \|\| b}` | Short-circuit evaluation |
|
|
701
|
+
| **Comparison** | `{count > 0}`, `{status === 'active'}` | `==`, `===`, `!=`, `!==`, `<`, `>`, `<=`, `>=` |
|
|
702
|
+
| **Arithmetic** | `{price * quantity}` | `+`, `-`, `*`, `/`, `%` |
|
|
703
|
+
| **Optional Chaining** | `{user?.profile?.name}` | Safe property access |
|
|
704
|
+
| **Nullish Coalescing** | `{value ?? 'default'}` | Default for null/undefined |
|
|
705
|
+
| **Ternary** | `{isActive ? 'Yes' : 'No'}` | Conditional value |
|
|
706
|
+
| **Array Access** | `{items[0]}` | Index-based access |
|
|
707
|
+
| **String Concatenation** | `{firstName + ' ' + lastName}` | String joining |
|
|
708
|
+
|
|
709
|
+
### Best Practices for Complex Expressions
|
|
710
|
+
|
|
711
|
+
```html
|
|
712
|
+
<!-- ✅ GOOD: Simple inline logic -->
|
|
713
|
+
<template lwc:if={!isLoading && hasData}>
|
|
714
|
+
...
|
|
715
|
+
</template>
|
|
716
|
+
|
|
717
|
+
<!-- ✅ GOOD: Optional chaining for safety -->
|
|
718
|
+
<span>{account?.Owner?.Name}</span>
|
|
719
|
+
|
|
720
|
+
<!-- ⚠️ CAUTION: Keep expressions readable -->
|
|
721
|
+
<!-- If expression is long, consider a getter for maintainability -->
|
|
722
|
+
<template lwc:if={isEditable && hasPermission && !isLocked && status === 'draft'}>
|
|
723
|
+
<!-- Consider: get canEdit() { return ...; } -->
|
|
724
|
+
</template>
|
|
725
|
+
|
|
726
|
+
<!-- ❌ AVOID: Side effects in expressions -->
|
|
727
|
+
<!-- Don't call methods that modify state -->
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
### Migration Strategy
|
|
731
|
+
|
|
732
|
+
1. **New code**: Use complex expressions for simple conditions
|
|
733
|
+
2. **Existing code**: Keep getters that have unit tests
|
|
734
|
+
3. **Complex logic**: Continue using getters for maintainability
|
|
735
|
+
4. **Document**: Mark complex expressions in templates for review when GA
|
|
736
|
+
|
|
737
|
+
### Limitations (Beta)
|
|
738
|
+
|
|
739
|
+
- No function calls in expressions (use getters)
|
|
740
|
+
- No template literals with `${}` interpolation
|
|
741
|
+
- Cannot reference `this` directly
|
|
742
|
+
- No destructuring in expressions
|
|
743
|
+
|
|
744
|
+
---
|
|
745
|
+
|
|
746
|
+
## Template Directives
|
|
747
|
+
|
|
748
|
+
### Conditional Rendering: Legacy → Modern
|
|
749
|
+
|
|
750
|
+
Always use `lwc:if`, `lwc:elseif`, `lwc:else` instead of the deprecated `if:true` / `if:false` directives.
|
|
751
|
+
|
|
752
|
+
```html
|
|
753
|
+
<!-- ❌ Legacy (deprecated) -->
|
|
754
|
+
<template if:true={isLoading}>
|
|
755
|
+
<lightning-spinner></lightning-spinner>
|
|
756
|
+
</template>
|
|
757
|
+
<template if:false={isLoading}>
|
|
758
|
+
<c-data-view data={records}></c-data-view>
|
|
759
|
+
</template>
|
|
760
|
+
|
|
761
|
+
<!-- ✅ Modern -->
|
|
762
|
+
<template lwc:if={isLoading}>
|
|
763
|
+
<lightning-spinner></lightning-spinner>
|
|
764
|
+
</template>
|
|
765
|
+
<template lwc:elseif={error}>
|
|
766
|
+
<c-error-panel errors={error}></c-error-panel>
|
|
767
|
+
</template>
|
|
768
|
+
<template lwc:else>
|
|
769
|
+
<c-data-view data={records}></c-data-view>
|
|
770
|
+
</template>
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
**Rules**: Conditional directives are valid on `<template>`, standard HTML tags, custom components, and base components. All elements in a conditional group must be siblings at the same DOM level.
|
|
774
|
+
|
|
775
|
+
### List Rendering
|
|
776
|
+
|
|
777
|
+
#### for:each
|
|
778
|
+
|
|
779
|
+
Every `for:each` must be paired with `for:item`. The `key` attribute must use a stable unique identifier — always `key={item.id}`, never an index.
|
|
780
|
+
|
|
781
|
+
```html
|
|
782
|
+
<!-- ✅ GOOD -->
|
|
783
|
+
<template for:each={accounts} for:item="account">
|
|
784
|
+
<c-account-card key={account.Id} account={account}></c-account-card>
|
|
785
|
+
</template>
|
|
786
|
+
|
|
787
|
+
<!-- ❌ BAD: key={index} or key={account.Name} -->
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
#### iterator Directive
|
|
791
|
+
|
|
792
|
+
Use `iterator` when you need access to `.first` or `.last` metadata for conditional styling.
|
|
793
|
+
|
|
794
|
+
```html
|
|
795
|
+
<template iterator:it={contacts}>
|
|
796
|
+
<div key={it.value.Id}>
|
|
797
|
+
{it.value.Name}
|
|
798
|
+
</div>
|
|
799
|
+
</template>
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
**Iterator name must be lowercase**. Access item data via `{iteratorname}.value.property` and metadata via `.index`, `.first`, `.last`.
|
|
803
|
+
|
|
804
|
+
#### Nested Loop Rules
|
|
805
|
+
|
|
806
|
+
Use distinct `for:item` or `iterator` names in nested loops to avoid variable shadowing:
|
|
807
|
+
|
|
808
|
+
```html
|
|
809
|
+
<!-- ✅ Distinct names -->
|
|
810
|
+
<template for:each={departments} for:item="dept">
|
|
811
|
+
<div key={dept.Id}>
|
|
812
|
+
<template for:each={dept.Employees} for:item="emp">
|
|
813
|
+
<span key={emp.Id}>{emp.Name}</span>
|
|
814
|
+
</template>
|
|
815
|
+
</div>
|
|
816
|
+
</template>
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
### Multiple Template Rendering
|
|
820
|
+
|
|
821
|
+
When a component needs to switch between entirely different layouts, import multiple HTML templates and return the appropriate one from `render()`.
|
|
822
|
+
|
|
823
|
+
```javascript
|
|
824
|
+
import defaultTemplate from './myComponent.html';
|
|
825
|
+
import editTemplate from './myComponentEdit.html';
|
|
826
|
+
|
|
827
|
+
export default class MyComponent extends LightningElement {
|
|
828
|
+
isEditing = false;
|
|
829
|
+
|
|
830
|
+
render() {
|
|
831
|
+
return this.isEditing ? editTemplate : defaultTemplate;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
```
|
|
835
|
+
|
|
836
|
+
---
|
|
837
|
+
|
|
838
|
+
## Performance Optimization (PICKLES: Execution)
|
|
839
|
+
|
|
840
|
+
### Lifecycle Hook Guidance
|
|
841
|
+
|
|
842
|
+
| Hook | When to Use | Avoid |
|
|
843
|
+
|------|-------------|-------|
|
|
844
|
+
| `constructor()` | Initialize properties | DOM access (not ready) |
|
|
845
|
+
| `connectedCallback()` | Subscribe to events, fetch data | Heavy processing |
|
|
846
|
+
| `renderedCallback()` | DOM-dependent logic | Infinite loops, property changes |
|
|
847
|
+
| `disconnectedCallback()` | Cleanup subscriptions/listeners | Async operations |
|
|
848
|
+
|
|
849
|
+
### Lazy Loading
|
|
850
|
+
|
|
851
|
+
```html
|
|
852
|
+
<!-- Only render when needed -->
|
|
853
|
+
<template lwc:if={showDetails}>
|
|
854
|
+
<c-expensive-component record-id={recordId}></c-expensive-component>
|
|
855
|
+
</template>
|
|
856
|
+
```
|
|
857
|
+
|
|
858
|
+
### Efficient Rendering
|
|
859
|
+
|
|
860
|
+
```javascript
|
|
861
|
+
// Bad: Creates new array every render
|
|
862
|
+
get filteredItems() {
|
|
863
|
+
return this.items.filter(item => item.active);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// Good: Cache the result
|
|
867
|
+
_filteredItems;
|
|
868
|
+
_itemsHash;
|
|
869
|
+
|
|
870
|
+
get filteredItems() {
|
|
871
|
+
const currentHash = JSON.stringify(this.items);
|
|
872
|
+
if (currentHash !== this._itemsHash) {
|
|
873
|
+
this._filteredItems = this.items.filter(item => item.active);
|
|
874
|
+
this._itemsHash = currentHash;
|
|
875
|
+
}
|
|
876
|
+
return this._filteredItems;
|
|
877
|
+
}
|
|
878
|
+
```
|
|
879
|
+
|
|
880
|
+
### Virtual Scrolling
|
|
881
|
+
|
|
882
|
+
Use `lightning-datatable` with `enable-infinite-loading` for large datasets instead of rendering all items.
|
|
883
|
+
|
|
884
|
+
**For comprehensive performance patterns** (DOM optimization, event delegation, memory management, bundle size): see `references/performance-guide.md`
|
|
885
|
+
|
|
886
|
+
---
|
|
887
|
+
|
|
888
|
+
## Advanced Jest Testing Patterns
|
|
889
|
+
|
|
890
|
+
Based on [James Simone's advanced testing patterns](https://www.jamessimone.net/blog/joys-of-apex/advanced-lwc-jest-testing/).
|
|
891
|
+
|
|
892
|
+
### Render Cycle Helper
|
|
893
|
+
|
|
894
|
+
LWC re-rendering is asynchronous. Use this helper to document and await render cycles:
|
|
895
|
+
|
|
896
|
+
```javascript
|
|
897
|
+
// testUtils.js
|
|
898
|
+
export const runRenderingLifecycle = async (reasons = ['render']) => {
|
|
899
|
+
while (reasons.length > 0) {
|
|
900
|
+
await Promise.resolve(reasons.pop());
|
|
901
|
+
}
|
|
902
|
+
};
|
|
903
|
+
|
|
904
|
+
// Usage in tests
|
|
905
|
+
it('updates after property change', async () => {
|
|
906
|
+
const element = createElement('c-example', { is: Example });
|
|
907
|
+
document.body.appendChild(element);
|
|
908
|
+
|
|
909
|
+
element.greeting = 'new value';
|
|
910
|
+
await runRenderingLifecycle(['property change', 'render']);
|
|
911
|
+
|
|
912
|
+
expect(element.shadowRoot.querySelector('div').textContent).toBe('new value');
|
|
913
|
+
});
|
|
914
|
+
```
|
|
915
|
+
|
|
916
|
+
### Proxy Unboxing (Lightning Web Security)
|
|
917
|
+
|
|
918
|
+
Lightning Web Security proxifies objects. Unbox them for assertions:
|
|
919
|
+
|
|
920
|
+
```javascript
|
|
921
|
+
// LWS proxifies complex objects - unbox for comparison
|
|
922
|
+
const unboxedData = JSON.parse(JSON.stringify(component.data));
|
|
923
|
+
expect(unboxedData).toEqual(expectedData);
|
|
924
|
+
```
|
|
925
|
+
|
|
926
|
+
### DOM Cleanup Pattern
|
|
927
|
+
|
|
928
|
+
Clean up after each test to prevent state bleed:
|
|
929
|
+
|
|
930
|
+
```javascript
|
|
931
|
+
describe('c-my-component', () => {
|
|
932
|
+
afterEach(() => {
|
|
933
|
+
// Clean up DOM
|
|
934
|
+
while (document.body.firstChild) {
|
|
935
|
+
document.body.removeChild(document.body.firstChild);
|
|
936
|
+
}
|
|
937
|
+
jest.clearAllMocks();
|
|
938
|
+
});
|
|
939
|
+
});
|
|
940
|
+
```
|
|
941
|
+
|
|
942
|
+
### ResizeObserver Polyfill
|
|
943
|
+
|
|
944
|
+
Some components use ResizeObserver. Add polyfill in jest.setup.js:
|
|
945
|
+
|
|
946
|
+
```javascript
|
|
947
|
+
// jest.setup.js
|
|
948
|
+
if (!window.ResizeObserver) {
|
|
949
|
+
window.ResizeObserver = class ResizeObserver {
|
|
950
|
+
constructor(callback) {
|
|
951
|
+
this.callback = callback;
|
|
952
|
+
}
|
|
953
|
+
observe() {}
|
|
954
|
+
unobserve() {}
|
|
955
|
+
disconnect() {}
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
```
|
|
959
|
+
|
|
960
|
+
### Mocking Apex Methods
|
|
961
|
+
|
|
962
|
+
```javascript
|
|
963
|
+
jest.mock('@salesforce/apex/MyController.getData', () => ({
|
|
964
|
+
default: jest.fn()
|
|
965
|
+
}), { virtual: true });
|
|
966
|
+
|
|
967
|
+
// In test
|
|
968
|
+
import getData from '@salesforce/apex/MyController.getData';
|
|
969
|
+
|
|
970
|
+
it('displays data', async () => {
|
|
971
|
+
getData.mockResolvedValue(MOCK_DATA);
|
|
972
|
+
// ... test code
|
|
973
|
+
});
|
|
974
|
+
```
|
|
975
|
+
|
|
976
|
+
---
|
|
977
|
+
|
|
978
|
+
## Security Best Practices (PICKLES: Security)
|
|
979
|
+
|
|
980
|
+
### FLS Enforcement
|
|
981
|
+
|
|
982
|
+
```apex
|
|
983
|
+
// Always use SECURITY_ENFORCED or stripInaccessible
|
|
984
|
+
@AuraEnabled(cacheable=true)
|
|
985
|
+
public static List<Account> getAccounts() {
|
|
986
|
+
return [SELECT Id, Name FROM Account WITH SECURITY_ENFORCED];
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
// For DML operations
|
|
990
|
+
SObjectAccessDecision decision = Security.stripInaccessible(
|
|
991
|
+
AccessType.CREATABLE,
|
|
992
|
+
records
|
|
993
|
+
);
|
|
994
|
+
insert decision.getRecords();
|
|
995
|
+
```
|
|
996
|
+
|
|
997
|
+
### Input Sanitization
|
|
998
|
+
|
|
999
|
+
```apex
|
|
1000
|
+
// Apex should escape user input
|
|
1001
|
+
String searchKey = '%' + String.escapeSingleQuotes(searchTerm) + '%';
|
|
1002
|
+
```
|
|
1003
|
+
|
|
1004
|
+
### XSS Prevention
|
|
1005
|
+
|
|
1006
|
+
LWC automatically escapes content in templates. Never bypass this.
|
|
1007
|
+
|
|
1008
|
+
```html
|
|
1009
|
+
<!-- Safe: LWC auto-escapes -->
|
|
1010
|
+
<p>{userInput}</p>
|
|
1011
|
+
```
|
|
1012
|
+
|
|
1013
|
+
### Input Validation Patterns
|
|
1014
|
+
|
|
1015
|
+
#### Lightning Base Component Validation Attributes
|
|
1016
|
+
|
|
1017
|
+
Use built-in validation attributes on Lightning input components to enforce constraints declaratively:
|
|
1018
|
+
|
|
1019
|
+
```html
|
|
1020
|
+
<lightning-input
|
|
1021
|
+
label="Email"
|
|
1022
|
+
type="email"
|
|
1023
|
+
required
|
|
1024
|
+
max-length="255"
|
|
1025
|
+
message-when-value-missing="Email is required"
|
|
1026
|
+
message-when-pattern-mismatch="Enter a valid email address"
|
|
1027
|
+
onchange={handleEmailChange}>
|
|
1028
|
+
</lightning-input>
|
|
1029
|
+
```
|
|
1030
|
+
|
|
1031
|
+
#### Form Submission Validation
|
|
1032
|
+
|
|
1033
|
+
Always validate all inputs before processing a form submission:
|
|
1034
|
+
|
|
1035
|
+
```javascript
|
|
1036
|
+
handleSubmit() {
|
|
1037
|
+
const allValid = [...this.template.querySelectorAll('lightning-input')]
|
|
1038
|
+
.reduce((valid, input) => {
|
|
1039
|
+
input.reportValidity();
|
|
1040
|
+
return valid && input.checkValidity();
|
|
1041
|
+
}, true);
|
|
1042
|
+
|
|
1043
|
+
if (!allValid) {
|
|
1044
|
+
return; // Stop — validation errors displayed to user
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
this.saveRecord();
|
|
1048
|
+
}
|
|
1049
|
+
```
|
|
1050
|
+
|
|
1051
|
+
#### Custom Validation with setCustomValidity
|
|
1052
|
+
|
|
1053
|
+
```javascript
|
|
1054
|
+
handleBlur(event) {
|
|
1055
|
+
const input = event.target;
|
|
1056
|
+
if (input.value && !this.isUniqueName(input.value)) {
|
|
1057
|
+
input.setCustomValidity('This name is already in use');
|
|
1058
|
+
} else {
|
|
1059
|
+
input.setCustomValidity(''); // Always clear when valid
|
|
1060
|
+
}
|
|
1061
|
+
input.reportValidity();
|
|
1062
|
+
}
|
|
1063
|
+
```
|
|
1064
|
+
|
|
1065
|
+
### Scoped Module Imports
|
|
1066
|
+
|
|
1067
|
+
Always use static `@salesforce/` scoped imports instead of legacy Global Value Providers (`$Label`, `$Resource`, etc.)
|
|
1068
|
+
|
|
1069
|
+
---
|
|
1070
|
+
|
|
1071
|
+
## Accessibility (a11y)
|
|
1072
|
+
|
|
1073
|
+
### Required Practices
|
|
1074
|
+
|
|
1075
|
+
| Element | Requirement |
|
|
1076
|
+
|---------|-------------|
|
|
1077
|
+
| Buttons | `label` or `aria-label` |
|
|
1078
|
+
| Icons | `alternative-text` |
|
|
1079
|
+
| Form inputs | Associated `<label>` |
|
|
1080
|
+
| Dynamic content | `aria-live` region |
|
|
1081
|
+
| Loading states | `aria-busy="true"` |
|
|
1082
|
+
|
|
1083
|
+
### Keyboard Navigation
|
|
1084
|
+
|
|
1085
|
+
```javascript
|
|
1086
|
+
handleKeyDown(event) {
|
|
1087
|
+
switch (event.key) {
|
|
1088
|
+
case 'Enter':
|
|
1089
|
+
case ' ':
|
|
1090
|
+
this.handleSelect(event);
|
|
1091
|
+
break;
|
|
1092
|
+
case 'Escape':
|
|
1093
|
+
this.handleClose();
|
|
1094
|
+
break;
|
|
1095
|
+
case 'ArrowDown':
|
|
1096
|
+
this.focusNext();
|
|
1097
|
+
event.preventDefault();
|
|
1098
|
+
break;
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
```
|
|
1102
|
+
|
|
1103
|
+
### Focus Trap Pattern (for Modals)
|
|
1104
|
+
|
|
1105
|
+
Based on [James Simone's modal pattern](https://www.jamessimone.net/blog/joys-of-apex/lwc-composable-modal/):
|
|
1106
|
+
|
|
1107
|
+
```javascript
|
|
1108
|
+
_focusableElements = [];
|
|
1109
|
+
|
|
1110
|
+
_onOpen() {
|
|
1111
|
+
// Collect focusable elements
|
|
1112
|
+
this._focusableElements = [
|
|
1113
|
+
...this.querySelectorAll('.focusable'),
|
|
1114
|
+
...this.template.querySelectorAll('lightning-button, button, [tabindex="0"]')
|
|
1115
|
+
].filter(el => !el.disabled);
|
|
1116
|
+
|
|
1117
|
+
// Focus first element
|
|
1118
|
+
this._focusableElements[0]?.focus();
|
|
1119
|
+
|
|
1120
|
+
// Add ESC handler
|
|
1121
|
+
window.addEventListener('keyup', this._handleKeyUp);
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
_handleKeyUp = (event) => {
|
|
1125
|
+
if (event.code === 'Escape') {
|
|
1126
|
+
this.close();
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
disconnectedCallback() {
|
|
1131
|
+
window.removeEventListener('keyup', this._handleKeyUp);
|
|
1132
|
+
}
|
|
1133
|
+
```
|
|
1134
|
+
|
|
1135
|
+
---
|
|
1136
|
+
|
|
1137
|
+
## SLDS 2 & Dark Mode
|
|
1138
|
+
|
|
1139
|
+
### Dark Mode Checklist
|
|
1140
|
+
|
|
1141
|
+
- [ ] No hardcoded hex colors (`#FFFFFF`, `#333333`)
|
|
1142
|
+
- [ ] No hardcoded RGB/RGBA values
|
|
1143
|
+
- [ ] All colors use CSS variables (`var(--slds-g-color-*)`)
|
|
1144
|
+
- [ ] Fallback values provided for SLDS 1 compatibility
|
|
1145
|
+
- [ ] Icons use SLDS utility icons (auto-adjust for dark mode)
|
|
1146
|
+
|
|
1147
|
+
### SLDS 1 → SLDS 2 Migration
|
|
1148
|
+
|
|
1149
|
+
```css
|
|
1150
|
+
/* BEFORE (SLDS 1 - Deprecated) */
|
|
1151
|
+
.my-card {
|
|
1152
|
+
background-color: #ffffff;
|
|
1153
|
+
color: #333333;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
/* AFTER (SLDS 2 - Dark Mode Ready) */
|
|
1157
|
+
.my-card {
|
|
1158
|
+
background-color: var(--slds-g-color-surface-container-1, #ffffff);
|
|
1159
|
+
color: var(--slds-g-color-on-surface, #181818);
|
|
1160
|
+
}
|
|
1161
|
+
```
|
|
1162
|
+
|
|
1163
|
+
### Key Global Styling Hooks
|
|
1164
|
+
|
|
1165
|
+
| Category | SLDS 2 Variable |
|
|
1166
|
+
|----------|-----------------|
|
|
1167
|
+
| Surface | `--slds-g-color-surface-1` to `-4` |
|
|
1168
|
+
| Text | `--slds-g-color-on-surface` |
|
|
1169
|
+
| Border | `--slds-g-color-border-1`, `-2` |
|
|
1170
|
+
| Spacing | `--slds-g-spacing-0` to `-12` |
|
|
1171
|
+
|
|
1172
|
+
**Important**: `--slds-c-*` (component-level hooks) are NOT supported in SLDS 2 yet.
|
|
1173
|
+
|
|
1174
|
+
---
|
|
1175
|
+
|
|
1176
|
+
## CSS Isolation & Scoping
|
|
1177
|
+
|
|
1178
|
+
LWC uses Shadow DOM for style encapsulation. Follow these rules to prevent style leakage and collisions.
|
|
1179
|
+
|
|
1180
|
+
### CSS Selector Rules
|
|
1181
|
+
|
|
1182
|
+
| Pattern | Status | Reason |
|
|
1183
|
+
|---------|--------|--------|
|
|
1184
|
+
| `:host` | ✅ Use | Targets the component's root element |
|
|
1185
|
+
| `:host(.modifier)` | ✅ Use | Conditional styling based on host class |
|
|
1186
|
+
| `.my-class` | ✅ Use | Class selectors scoped automatically |
|
|
1187
|
+
| `*` (universal) | ❌ Avoid | Can leak outside component scope |
|
|
1188
|
+
| `#my-id` | ❌ Avoid | LWC transforms IDs to globally unique values |
|
|
1189
|
+
| `c-my-component` | ❌ Avoid | Use `:host` instead of component name |
|
|
1190
|
+
| `:host-context()` | ❌ Not supported | Use `:host` instead |
|
|
1191
|
+
| `lightning-button` | ❌ Avoid | Cannot override base component internals |
|
|
1192
|
+
| `.slds-button` | ❌ Avoid | Cannot replace or override SLDS classes |
|
|
1193
|
+
|
|
1194
|
+
```css
|
|
1195
|
+
/* ❌ BAD: Universal selector leaks */
|
|
1196
|
+
* { font-family: Arial, sans-serif; }
|
|
1197
|
+
|
|
1198
|
+
/* ✅ GOOD: Scoped universal */
|
|
1199
|
+
:host * { font-family: Arial, sans-serif; }
|
|
1200
|
+
|
|
1201
|
+
/* ❌ BAD: Component name as selector */
|
|
1202
|
+
c-my-component { display: flex; }
|
|
1203
|
+
|
|
1204
|
+
/* ✅ GOOD: :host for component-level styles */
|
|
1205
|
+
:host { display: flex; }
|
|
1206
|
+
|
|
1207
|
+
/* ❌ BAD: Overriding base component or SLDS */
|
|
1208
|
+
lightning-button { background-color: red; }
|
|
1209
|
+
.slds-button { background-color: purple; }
|
|
1210
|
+
|
|
1211
|
+
/* ✅ GOOD: Use styling hooks */
|
|
1212
|
+
:host {
|
|
1213
|
+
--slds-c-button-brand-color-background: red;
|
|
1214
|
+
}
|
|
1215
|
+
```
|
|
1216
|
+
|
|
1217
|
+
### Avoid `!important` Overuse
|
|
1218
|
+
|
|
1219
|
+
Rely on proper specificity rather than `!important` declarations. Excessive `!important` interferes with parent component styling and makes future maintenance difficult.
|
|
1220
|
+
|
|
1221
|
+
### Never Rely on Compiler-Generated Scope Tokens
|
|
1222
|
+
|
|
1223
|
+
```css
|
|
1224
|
+
/* ❌ BAD: Brittle — token changes across builds */
|
|
1225
|
+
c-child[lwc-2j48dfhd928c-host] { padding: 1rem; }
|
|
1226
|
+
|
|
1227
|
+
/* ✅ GOOD */
|
|
1228
|
+
:host { padding: 1rem; }
|
|
1229
|
+
```
|
|
1230
|
+
|
|
1231
|
+
---
|
|
1232
|
+
|
|
1233
|
+
## Testing Checklist
|
|
1234
|
+
|
|
1235
|
+
### Unit Test Coverage
|
|
1236
|
+
|
|
1237
|
+
- [ ] Component renders without errors
|
|
1238
|
+
- [ ] Data displays correctly when loaded
|
|
1239
|
+
- [ ] Error state displays when fetch fails
|
|
1240
|
+
- [ ] Empty state displays when no data
|
|
1241
|
+
- [ ] Events dispatch with correct payload
|
|
1242
|
+
- [ ] User interactions work correctly
|
|
1243
|
+
- [ ] Loading states are shown/hidden appropriately
|
|
1244
|
+
|
|
1245
|
+
### Manual Testing
|
|
1246
|
+
|
|
1247
|
+
- [ ] Works in Lightning Experience
|
|
1248
|
+
- [ ] Works in Salesforce Mobile
|
|
1249
|
+
- [ ] Works in Experience Cloud (if targeted)
|
|
1250
|
+
- [ ] Works in Dark Mode (SLDS 2)
|
|
1251
|
+
- [ ] Keyboard navigation works
|
|
1252
|
+
- [ ] Screen reader announces properly
|
|
1253
|
+
- [ ] No console errors
|
|
1254
|
+
- [ ] Performance acceptable with real data
|
|
1255
|
+
|
|
1256
|
+
---
|
|
1257
|
+
|
|
1258
|
+
## Common Mistakes
|
|
1259
|
+
|
|
1260
|
+
### 1. Modifying @api Properties
|
|
1261
|
+
|
|
1262
|
+
```javascript
|
|
1263
|
+
// ❌ BAD
|
|
1264
|
+
@api items;
|
|
1265
|
+
handleClick() {
|
|
1266
|
+
this.items.push(newItem); // Mutation!
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
// ✅ GOOD
|
|
1270
|
+
handleClick() {
|
|
1271
|
+
this.items = [...this.items, newItem];
|
|
1272
|
+
}
|
|
1273
|
+
```
|
|
1274
|
+
|
|
1275
|
+
### 2. Forgetting to Clean Up
|
|
1276
|
+
|
|
1277
|
+
```javascript
|
|
1278
|
+
// ❌ BAD: Memory leak
|
|
1279
|
+
connectedCallback() {
|
|
1280
|
+
this.subscription = subscribe(...);
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
// ✅ GOOD
|
|
1284
|
+
disconnectedCallback() {
|
|
1285
|
+
unsubscribe(this.subscription);
|
|
1286
|
+
}
|
|
1287
|
+
```
|
|
1288
|
+
|
|
1289
|
+
### 3. Wire with Non-Reactive Parameters
|
|
1290
|
+
|
|
1291
|
+
```javascript
|
|
1292
|
+
// ❌ BAD
|
|
1293
|
+
let recordId = '001xxx';
|
|
1294
|
+
@wire(getRecord, { recordId: recordId })
|
|
1295
|
+
|
|
1296
|
+
// ✅ GOOD
|
|
1297
|
+
@api recordId;
|
|
1298
|
+
@wire(getRecord, { recordId: '$recordId' })
|
|
1299
|
+
```
|
|
1300
|
+
|
|
1301
|
+
---
|
|
1302
|
+
|
|
1303
|
+
## Resources
|
|
1304
|
+
|
|
1305
|
+
- [PICKLES Framework](https://www.salesforceben.com/the-ideal-framework-for-architecting-salesforce-lightning-web-components/) — David Picksley, Third Eye Consulting
|
|
1306
|
+
- [LWC Recipes (GitHub)](https://github.com/trailheadapps/lwc-recipes)
|
|
1307
|
+
- [SLDS 2 Transition Guide](https://www.lightningdesignsystem.com/2e1ef8501/p/8184ad-transition-to-slds-2)
|
|
1308
|
+
- [James Simone - Advanced Jest Testing](https://www.jamessimone.net/blog/joys-of-apex/advanced-lwc-jest-testing/)
|
|
1309
|
+
- [James Simone - Composable Modal](https://www.jamessimone.net/blog/joys-of-apex/lwc-composable-modal/)
|
|
1310
|
+
- [SLDS Styling Hooks](https://developer.salesforce.com/docs/platform/lwc/guide/create-components-css-custom-properties.html)
|