agent-docs 1.1.0 → 1.3.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.
@@ -0,0 +1,314 @@
1
+ # LWC HTML Templates
2
+
3
+ > **Version**: 1.0.0
4
+
5
+ ## File Structure
6
+
7
+ - Location: `lwc/<ComponentName>/<ComponentName>.html`
8
+ - Additional HTML files allowed for multiple template rendering (advanced)
9
+ - Leverage virtual DOM; avoid manual DOM manipulation in JavaScript
10
+
11
+ ## Template Structure
12
+
13
+ - **Root element:** `<template>` (renders as `<namespace-component-name>`)
14
+ - **Nested `<template>` tags:** required for directives; only allowed attributes:
15
+ - `for:each`, `iterator:iteratorname`, `lwc:if`, `lwc:else`, `lwc:elseif`, `if:true|false`
16
+ - No other directives or HTML attributes (e.g., no `class` on nested `<template>`)
17
+ - **No inline `<style>` or `<script>` tags** — use separate CSS/JS files
18
+ - Follow Lightning Design System patterns and accessibility guidelines
19
+
20
+ ## Data Binding & Expressions
21
+
22
+ | Syntax | Usage |
23
+ |--------|-------|
24
+ | `{property}` | Bind data (no spaces around property) |
25
+ | `{data.name}` | Dot notation supported |
26
+ | `{!property}` | Two-way binding (form inputs) |
27
+ | `{handlerMethod}` | Event handler binding |
28
+
29
+ ### Allowed Expression Syntax
30
+
31
+ The `{expression}` binding syntax **only** supports:
32
+
33
+ - **Simple property references:** `{myProperty}`
34
+ - **Dot notation paths:** `{contact.name}`, `{account.owner.email}`
35
+ - **Method references for events:** `onclick={handleClick}`
36
+
37
+ **That's it.** No operators, no function calls, no array indexing, no ternaries.
38
+
39
+ ### ❌ What's NOT Allowed (Common AI Agent Mistakes)
40
+
41
+ ```html
42
+ <!-- ❌ Logical operators -->
43
+ {isReadOnly || isLoading}
44
+ {isActive && isVisible}
45
+
46
+ <!-- ❌ Negation operator -->
47
+ {!isDisabled}
48
+
49
+ <!-- ❌ Ternary expressions -->
50
+ {isActive ? 'active' : 'inactive'}
51
+
52
+ <!-- ❌ Arithmetic -->
53
+ {count + 1}
54
+ {price * quantity}
55
+
56
+ <!-- ❌ Array indexing -->
57
+ {items[0].name}
58
+ {person[2].name['John']}
59
+
60
+ <!-- ❌ Function calls in templates -->
61
+ {formatDate(startDate)}
62
+ {calculateTotal()}
63
+
64
+ <!-- ❌ String concatenation -->
65
+ {'Hello ' + name}
66
+ {`Item: ${itemName}`}
67
+
68
+ <!-- ❌ Comparisons -->
69
+ {count > 0}
70
+ {status === 'active'}
71
+
72
+ <!-- ❌ Nullish coalescing / optional chaining in binding -->
73
+ {user?.name}
74
+ {value ?? 'default'}
75
+ ```
76
+
77
+ ### ✅ The Solution: Use JavaScript Getters
78
+
79
+ All computed logic **must** be moved to getters in the JavaScript class:
80
+
81
+ **JavaScript (myComponent.js):**
82
+ ```javascript
83
+ import { LightningElement, api, track } from 'lwc';
84
+
85
+ export default class MyComponent extends LightningElement {
86
+ @api isReadOnly = false;
87
+ @api isLoading = false;
88
+ @track items = [];
89
+
90
+ // ✅ Logical operators → getter
91
+ get isDisabled() {
92
+ return this.isReadOnly || this.isLoading;
93
+ }
94
+
95
+ // ✅ Negation → getter
96
+ get isEnabled() {
97
+ return !this.isDisabled;
98
+ }
99
+
100
+ // ✅ Ternary → getter
101
+ get buttonLabel() {
102
+ return this.isLoading ? 'Loading...' : 'Submit';
103
+ }
104
+
105
+ // ✅ Arithmetic → getter
106
+ get itemCountPlusOne() {
107
+ return this.count + 1;
108
+ }
109
+
110
+ // ✅ Array indexing → getter
111
+ get firstItemName() {
112
+ return this.items[0]?.name || '';
113
+ }
114
+
115
+ // ✅ String formatting → getter
116
+ get formattedCount() {
117
+ return `${this.count} items`;
118
+ }
119
+
120
+ // ✅ Comparisons for conditional rendering → getter
121
+ get hasItems() {
122
+ return this.items.length > 0;
123
+ }
124
+
125
+ // ✅ Complex class computation → getter
126
+ get containerClass() {
127
+ return {
128
+ 'slds-box': true,
129
+ 'slds-theme_shade': this.isActive,
130
+ 'slds-hide': !this.isVisible
131
+ };
132
+ }
133
+ }
134
+ ```
135
+
136
+ **HTML (myComponent.html):**
137
+ ```html
138
+ <template>
139
+ <template lwc:if={hasItems}>
140
+ <div class={containerClass}>
141
+ <p>{formattedCount}</p>
142
+ <p>First item: {firstItemName}</p>
143
+ </div>
144
+ </template>
145
+
146
+ <lightning-button
147
+ label={buttonLabel}
148
+ disabled={isDisabled}
149
+ onclick={handleClick}>
150
+ </lightning-button>
151
+ </template>
152
+ ```
153
+
154
+ ### Why This Design?
155
+
156
+ Salesforce made this intentional choice for:
157
+
158
+ | Reason | Explanation |
159
+ |--------|-------------|
160
+ | **Performance** | Simple property lookups are fast; no runtime expression parsing/evaluation |
161
+ | **Security** | No risk of template injection or expression-based exploits |
162
+ | **Predictability** | Reactivity is straightforward—change a property, component re-renders |
163
+ | **Testability** | All logic lives in unit-testable JavaScript, not scattered in templates |
164
+ | **Debugging** | Stack traces point to JS files, not opaque template expressions |
165
+
166
+ ### AI Agent Rule Summary
167
+
168
+ > **LWC Template Expression Rule:** The `{...}` binding syntax accepts ONLY property names and dot-notation paths. Any logic requiring operators (`||`, `&&`, `?:`, `+`, `>`, `===`, etc.), function calls, array indexing, or string interpolation MUST be implemented as a getter in the JavaScript class.
169
+
170
+ ```
171
+ Template binding: {propertyName} or {object.nested.property}
172
+ Computed logic: get computedProperty() { return /* any JS expression */; }
173
+ ```
174
+
175
+ ## Conditional Rendering
176
+
177
+ Use `lwc:if`, `lwc:elseif`, `lwc:else` directives (prefer over multiple templates for simple conditions):
178
+
179
+ ```html
180
+ <template lwc:if={condition}>...</template>
181
+ <template lwc:elseif={otherCondition}>...</template>
182
+ <template lwc:else>...</template>
183
+ ```
184
+
185
+ **Note:** The condition must be a simple property reference or getter—not an expression:
186
+
187
+ ```html
188
+ <!-- ❌ Invalid -->
189
+ <template lwc:if={items.length > 0}>
190
+
191
+ <!-- ✅ Valid — use a getter -->
192
+ <template lwc:if={hasItems}>
193
+ ```
194
+
195
+ ## List Rendering
196
+
197
+ ### for:each
198
+ ```html
199
+ <template for:each={array} for:item="item">
200
+ <div key={item.uniqueId}>{item.property}</div>
201
+ </template>
202
+ ```
203
+ - `key` required: string/number, **not** index or object
204
+ - Access current item via `for:item="itemName"` → `{itemName.property}`
205
+
206
+ ### iterator
207
+ ```html
208
+ <template iterator:it={array}>
209
+ <div key={it.value.uniqueId}>{it.value.property}</div>
210
+ </template>
211
+ ```
212
+ - Iterator name must be lowercase
213
+ - Properties: `{it.value.property}`, `{it.index}`, `{it.first}`, `{it.last}`
214
+ - Combine with `lwc:if` for first/last styling: `lwc:if={it.first}`
215
+
216
+ ## Multiple Template Rendering (Advanced)
217
+
218
+ - Import templates: `import templateOne from "./templateOne.html"`
219
+ - Override `render()` to return template based on state
220
+ - CSS must match template filename: `templateTwo.html` → `templateTwo.css`
221
+ - Default: `componentName.html` when no `render()` override
222
+ - **Prefer `lwc:if` for simple variations; use multiple templates for significantly different layouts**
223
+
224
+ ## Class Object Binding (LWC API v62.0+)
225
+
226
+ Bind dynamic classes using arrays or objects instead of string concatenation:
227
+
228
+ | Input | Output |
229
+ |-------|--------|
230
+ | `["highlight", "yellow"]` | `class="highlight yellow"` |
231
+ | `{highlight: true, hidden: false}` | `class="highlight"` |
232
+
233
+ - Booleans, numbers, functions render as empty string (use `String(value)` if needed)
234
+ - Use getters to compute complex class combinations
235
+
236
+ **Example with getter:**
237
+ ```javascript
238
+ get cardClasses() {
239
+ return {
240
+ 'slds-card': true,
241
+ 'slds-card_boundary': this.hasBorder,
242
+ 'custom-highlight': this.isHighlighted
243
+ };
244
+ }
245
+ ```
246
+
247
+ ```html
248
+ <div class={cardClasses}>...</div>
249
+ ```
250
+
251
+ ## Inline Style Binding
252
+
253
+ - Syntax: `style={computedStyles}`
254
+ - Getter returns semi-colon separated properties: `width: 50%; font-size: 20px`
255
+ - Use kebab-case CSS properties (`font-size`, not `fontSize`)
256
+ - **Prefer CSS classes over inline styles**; use inline for dynamic/computed values only
257
+
258
+ **Example:**
259
+ ```javascript
260
+ get progressBarStyle() {
261
+ return `width: ${this.progressPercent}%; background-color: ${this.barColor}`;
262
+ }
263
+ ```
264
+
265
+ ```html
266
+ <div class="progress-bar" style={progressBarStyle}></div>
267
+ ```
268
+
269
+ ## Event Handling
270
+
271
+ - Bind handlers via method reference: `onclick={handleClick}`
272
+ - No inline functions in templates
273
+ - Access values via `event.target.value`
274
+ - Custom events: extend `LightningElement`, use proper event naming
275
+
276
+ ```html
277
+ <!-- ❌ Invalid — no inline functions -->
278
+ <button onclick={() => this.handleClick()}>
279
+
280
+ <!-- ✅ Valid — method reference -->
281
+ <button onclick={handleClick}>
282
+ ```
283
+
284
+ ## Accessibility
285
+
286
+ - Include proper ARIA attributes
287
+ - Use semantic HTML elements
288
+ - Ensure keyboard navigation for interactive elements
289
+
290
+ ## Performance
291
+
292
+ - Minimize DOM manipulation
293
+ - Use lazy loading / pagination for large lists
294
+ - Avoid unnecessary rerenders by optimizing data binding
295
+ - Getters are re-evaluated on every render—keep them lightweight or cache expensive computations
296
+
297
+ ## Validation Checklist
298
+
299
+ - [ ] File path: `lwc/<ComponentName>/<ComponentName>.html`
300
+ - [ ] Root element is `<template>`
301
+ - [ ] Nested `<template>` tags include only allowed directives
302
+ - [ ] Nested `<template>` tags have no other attributes (e.g., no `class`)
303
+ - [ ] No inline `<style>` or `<script>` tags
304
+ - [ ] No manual DOM manipulation in JS
305
+ - [ ] Data binding: `{property}` syntax, no spaces
306
+ - [ ] **No computed expressions in templates** (no operators, function calls, array indexing)
307
+ - [ ] **All computed logic implemented as getters in JS class**
308
+ - [ ] `for:each`: has `for:item` and unique `key` (string/number)
309
+ - [ ] `iterator`: lowercase name, unique `key={it.value.uniqueId}`
310
+ - [ ] Multiple templates: proper imports, `render()` override, matching CSS filenames
311
+ - [ ] Class binding follows v62.0+ semantics (arrays/objects via getters)
312
+ - [ ] Inline styles: `style={getter}`, kebab-case properties
313
+ - [ ] Valid HTML syntax (use Salesforce Extensions Pack for validation)
314
+ - [ ] Follows accessibility and performance best practices