@pure-ds/core 0.4.23 β 0.4.25
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/.cursorrules +250 -2
- package/.github/copilot-instructions.md +290 -2
- package/dist/types/pds.d.ts +109 -408
- package/dist/types/public/assets/js/pds.d.ts +2 -2
- package/dist/types/public/assets/js/pds.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-form.d.ts.map +1 -1
- package/dist/types/src/js/common/toast.d.ts +93 -0
- package/dist/types/src/js/common/toast.d.ts.map +1 -0
- package/dist/types/src/js/pds-core/pds-config.d.ts +0 -1
- package/dist/types/src/js/pds-core/pds-config.d.ts.map +1 -1
- package/dist/types/src/js/pds.d.ts.map +1 -1
- package/package.json +4 -3
- package/packages/pds-cli/bin/pds-init-config.js +34 -0
- package/packages/pds-cli/bin/{postinstall.js β postinstall.mjs} +85 -1
- package/public/assets/js/app.js +13 -8
- package/public/assets/js/pds.js +14 -9
- package/public/assets/pds/components/pds-form.js +29 -8
- package/readme.md +83 -3
- package/src/js/pds-core/pds-config.js +1 -2
- package/src/js/pds.d.ts +62 -0
- package/src/js/pds.js +23 -4
package/.cursorrules
CHANGED
|
@@ -41,6 +41,210 @@ PDS follows the [Pure Web Manifesto](https://pureweb.dev/manifesto): "The browse
|
|
|
41
41
|
- `public/assets/pds/vscode-custom-data.json`
|
|
42
42
|
- `src/js/pds-core/pds-ontology.js`
|
|
43
43
|
|
|
44
|
+
**Path resolution helper:** When looking up SSoT files:
|
|
45
|
+
1. First check if `node_modules/@pure-ds/core/` exists (consuming project)
|
|
46
|
+
2. Otherwise use workspace root paths (pure-ds development)
|
|
47
|
+
3. Prefer reading actual files over guessing - the data is authoritative
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## π pds-form Best Practices
|
|
52
|
+
|
|
53
|
+
**When generating pds-form code, ALWAYS follow these patterns:**
|
|
54
|
+
|
|
55
|
+
### 1. Event Handling - Use `pw:submit`, NOT `submit`
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
// β
CORRECT: Listen to pw:submit custom event
|
|
59
|
+
form.addEventListener('pw:submit', async (e) => {
|
|
60
|
+
const { json, formData, valid, issues } = e.detail;
|
|
61
|
+
if (valid) {
|
|
62
|
+
// Handle submission with json or formData
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// β WRONG: Native submit event
|
|
67
|
+
form.addEventListener('submit', (e) => { /* Won't work */ });
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 2. Submit Button Progress - Add `btn-working` automatically
|
|
71
|
+
|
|
72
|
+
**When user requests a form with async submission, ALWAYS:**
|
|
73
|
+
- Add `btn-working` class to submit button during processing
|
|
74
|
+
- Remove it when done (PDS automatically shows spinner icon)
|
|
75
|
+
- Use a realistic 2-3 second delay for demos
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
// β
CORRECT: Auto-add progress state
|
|
79
|
+
form.addEventListener('pw:submit', async (e) => {
|
|
80
|
+
const submitBtn = form.querySelector('button[type="submit"]');
|
|
81
|
+
submitBtn?.classList.add('btn-working');
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
await simulateSubmit(e.detail.json); // 2-3 second promise
|
|
85
|
+
await PDS.toast('Submitted successfully!', { type: 'success' });
|
|
86
|
+
} finally {
|
|
87
|
+
submitBtn?.classList.remove('btn-working');
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
async function simulateSubmit(data) {
|
|
92
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
93
|
+
console.log('Submitted:', data);
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 3. Progressive Enhancement - Add `data-required` to form wrapper
|
|
98
|
+
|
|
99
|
+
```html
|
|
100
|
+
<!-- β
CORRECT: Wrap pds-form in form[data-required] -->
|
|
101
|
+
<form data-required>
|
|
102
|
+
<pds-form id="myForm" hide-actions></pds-form>
|
|
103
|
+
<div class="form-actions">
|
|
104
|
+
<button type="submit" class="btn-primary">Submit</button>
|
|
105
|
+
</div>
|
|
106
|
+
</form>
|
|
107
|
+
|
|
108
|
+
<!-- β WRONG: No data-required enhancement -->
|
|
109
|
+
<pds-form id="myForm"></pds-form>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### 4. JSON Schema - Use `examples` for placeholders
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
// β
CORRECT: Use examples array for placeholders
|
|
116
|
+
const schema = {
|
|
117
|
+
type: "object",
|
|
118
|
+
properties: {
|
|
119
|
+
name: {
|
|
120
|
+
type: "string",
|
|
121
|
+
title: "Full Name",
|
|
122
|
+
examples: ["John Doe"] // First example becomes placeholder
|
|
123
|
+
},
|
|
124
|
+
email: {
|
|
125
|
+
type: "string",
|
|
126
|
+
format: "email",
|
|
127
|
+
title: "Email",
|
|
128
|
+
examples: ["user@example.com"]
|
|
129
|
+
},
|
|
130
|
+
age: {
|
|
131
|
+
type: "integer",
|
|
132
|
+
title: "Age",
|
|
133
|
+
examples: [25] // Works for numbers too
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// β WRONG: No placeholders or using wrong property
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 5. UI Schema - Infer smart icons automatically
|
|
142
|
+
|
|
143
|
+
**Common field β icon mappings (use these by default):**
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
const smartIcons = {
|
|
147
|
+
email: 'envelope',
|
|
148
|
+
phone: 'phone',
|
|
149
|
+
name: 'user',
|
|
150
|
+
password: 'lock',
|
|
151
|
+
search: 'search',
|
|
152
|
+
message: 'message',
|
|
153
|
+
comment: 'comment',
|
|
154
|
+
address: 'map-marker',
|
|
155
|
+
website: 'link',
|
|
156
|
+
date: 'calendar',
|
|
157
|
+
time: 'clock',
|
|
158
|
+
subject: 'tag',
|
|
159
|
+
priority: 'flag',
|
|
160
|
+
category: 'folder',
|
|
161
|
+
file: 'file',
|
|
162
|
+
image: 'image'
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const uiSchema = {
|
|
166
|
+
email: {
|
|
167
|
+
'ui:widget': 'email',
|
|
168
|
+
'ui:placeholder': 'user@example.com',
|
|
169
|
+
'ui:icon': 'envelope', // Auto-infer
|
|
170
|
+
'ui:autocomplete': 'email'
|
|
171
|
+
},
|
|
172
|
+
phone: {
|
|
173
|
+
'ui:widget': 'tel',
|
|
174
|
+
'ui:icon': 'phone',
|
|
175
|
+
'ui:autocomplete': 'tel'
|
|
176
|
+
},
|
|
177
|
+
message: {
|
|
178
|
+
'ui:widget': 'textarea',
|
|
179
|
+
'ui:rows': 4,
|
|
180
|
+
'ui:icon': 'message'
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### 6. Complete Working Example
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
// Schema with examples for placeholders
|
|
189
|
+
const contactSchema = {
|
|
190
|
+
type: "object",
|
|
191
|
+
required: ["name", "email", "message"],
|
|
192
|
+
properties: {
|
|
193
|
+
name: {
|
|
194
|
+
type: "string",
|
|
195
|
+
title: "Name",
|
|
196
|
+
minLength: 2,
|
|
197
|
+
examples: ["John Doe"]
|
|
198
|
+
},
|
|
199
|
+
email: {
|
|
200
|
+
type: "string",
|
|
201
|
+
format: "email",
|
|
202
|
+
title: "Email",
|
|
203
|
+
examples: ["user@example.com"]
|
|
204
|
+
},
|
|
205
|
+
message: {
|
|
206
|
+
type: "string",
|
|
207
|
+
title: "Message",
|
|
208
|
+
minLength: 10,
|
|
209
|
+
examples: ["Your message here..."]
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
// UI schema with smart icons
|
|
215
|
+
const uiSchema = {
|
|
216
|
+
name: { 'ui:icon': 'user' },
|
|
217
|
+
email: { 'ui:icon': 'envelope' },
|
|
218
|
+
message: {
|
|
219
|
+
'ui:widget': 'textarea',
|
|
220
|
+
'ui:rows': 4,
|
|
221
|
+
'ui:icon': 'message'
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// Setup with pw:submit and btn-working
|
|
226
|
+
const form = document.getElementById('contactForm');
|
|
227
|
+
form.jsonSchema = contactSchema;
|
|
228
|
+
form.uiSchema = uiSchema;
|
|
229
|
+
|
|
230
|
+
form.addEventListener('pw:submit', async (e) => {
|
|
231
|
+
const submitBtn = form.querySelector('button[type="submit"]');
|
|
232
|
+
submitBtn?.classList.add('btn-working');
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
// Simulate 2s async operation
|
|
236
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
237
|
+
console.log('Submitted:', e.detail.json);
|
|
238
|
+
await PDS.toast('Message sent!', { type: 'success' });
|
|
239
|
+
form.reset();
|
|
240
|
+
} catch (error) {
|
|
241
|
+
await PDS.toast('Failed to send', { type: 'error' });
|
|
242
|
+
} finally {
|
|
243
|
+
submitBtn?.classList.remove('btn-working');
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
44
248
|
---
|
|
45
249
|
|
|
46
250
|
## π« Critical Anti-Patterns (NEVER DO THIS)
|
|
@@ -61,12 +265,33 @@ PDS follows the [Pure Web Manifesto](https://pureweb.dev/manifesto): "The browse
|
|
|
61
265
|
|
|
62
266
|
```javascript
|
|
63
267
|
// β NEVER: Browser dialogs - Use PDS.ask() and PDS.toast()
|
|
64
|
-
alert("message"); // β PDS.toast("message", { type: "info" })
|
|
268
|
+
alert("message"); // β await PDS.toast("message", { type: "info" })
|
|
65
269
|
confirm("sure?"); // β await PDS.ask("sure?", { type: "confirm" })
|
|
66
270
|
prompt("name?"); // β await PDS.ask("name?", { type: "prompt" })
|
|
67
271
|
|
|
68
272
|
// β NEVER: Manual dropdown/modal/tab implementations
|
|
69
273
|
// β Use <nav data-dropdown>, PDS.ask(), <pds-tabstrip>
|
|
274
|
+
|
|
275
|
+
// β NEVER: Access lazy-loaded component APIs before they're defined
|
|
276
|
+
const form = document.querySelector('pds-form');
|
|
277
|
+
form.getFormData(); // May fail - component not loaded yet
|
|
278
|
+
|
|
279
|
+
// β NEVER: Use native 'submit' event with pds-form
|
|
280
|
+
form.addEventListener('submit', (e) => { }); // β Use 'pw:submit'
|
|
281
|
+
|
|
282
|
+
// β NEVER: Forget btn-working class for async operations
|
|
283
|
+
button.onclick = async () => {
|
|
284
|
+
await fetch('/api'); // No loading indicator!
|
|
285
|
+
};
|
|
286
|
+
// β Add button.classList.add('btn-working') before, remove after
|
|
287
|
+
|
|
288
|
+
// β NEVER: Hardcode placeholders instead of using schema examples
|
|
289
|
+
const schema = {
|
|
290
|
+
properties: {
|
|
291
|
+
email: { type: "string" } // Missing examples!
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
// β Add examples: ["user@example.com"]
|
|
70
295
|
```
|
|
71
296
|
|
|
72
297
|
---
|
|
@@ -130,7 +355,7 @@ const confirmed = await PDS.ask("Delete this item?", {
|
|
|
130
355
|
buttons: { ok: { name: "Delete", variant: "danger" } }
|
|
131
356
|
});
|
|
132
357
|
|
|
133
|
-
PDS.toast("Saved successfully!", { type: "success" });
|
|
358
|
+
await PDS.toast("Saved successfully!", { type: "success" });
|
|
134
359
|
|
|
135
360
|
// Theme management
|
|
136
361
|
PDS.theme = 'dark'; // 'light' | 'dark' | 'system'
|
|
@@ -141,6 +366,19 @@ const results = await PDS.query("border gradient classes");
|
|
|
141
366
|
|
|
142
367
|
---
|
|
143
368
|
|
|
369
|
+
## π Additional Resources
|
|
370
|
+
|
|
371
|
+
**For comprehensive pds-form documentation:**
|
|
372
|
+
- Read [pds-form-docs.md](pds-form-docs.md) for complete API reference
|
|
373
|
+
- See [packages/pds-storybook/stories/components/PdsForm.stories.js](packages/pds-storybook/stories/components/PdsForm.stories.js) for real examples
|
|
374
|
+
- Check [custom-elements.json](custom-elements.json) for component API details
|
|
375
|
+
|
|
376
|
+
**For toast notifications:**
|
|
377
|
+
- Use `PDS.toast()` method (see [src/js/common/toast.js](src/js/common/toast.js) for implementation)
|
|
378
|
+
- Automatically ensures pds-toaster exists and is loaded before displaying
|
|
379
|
+
- See pds-toaster component API in [custom-elements.json](custom-elements.json)
|
|
380
|
+
---
|
|
381
|
+
|
|
144
382
|
## How to Look Things Up
|
|
145
383
|
|
|
146
384
|
| Question | Action |
|
|
@@ -166,3 +404,13 @@ Before generating code:
|
|
|
166
404
|
6. β
**Apply enhancements via data-* attributes** β See `pds-enhancer-metadata.js`
|
|
167
405
|
7. β
**Components as last resort** β Only when native HTML can't achieve it
|
|
168
406
|
8. β
**Prefer primitives** β `.card`, `.badge`, `.alert` over custom components
|
|
407
|
+
9. β
**Wait for lazy components** β Use `await customElements.whenDefined()` before accessing APIs
|
|
408
|
+
10. β
**Include import map** β When using `pds-form` or `pds-drawer`, ensure `#pds/lit` is mapped
|
|
409
|
+
|
|
410
|
+
**For pds-form specifically:**
|
|
411
|
+
|
|
412
|
+
11. β
**Use `pw:submit` event** β NOT native `submit` event
|
|
413
|
+
12. β
**Add `btn-working` class** β For async submit operations, add during processing
|
|
414
|
+
13. β
**Use `examples` in JSON schema** β First example becomes placeholder
|
|
415
|
+
14. β
**Add smart icons** β Infer icons based on field names (emailβenvelope, phoneβphone)
|
|
416
|
+
15. β
**Wrap in `form[data-required]`** β For asterisk enhancement on required fields
|
|
@@ -41,6 +41,210 @@ PDS follows the [Pure Web Manifesto](https://pureweb.dev/manifesto): "The browse
|
|
|
41
41
|
- `public/assets/pds/vscode-custom-data.json`
|
|
42
42
|
- `src/js/pds-core/pds-ontology.js`
|
|
43
43
|
|
|
44
|
+
**Path resolution helper:** When looking up SSoT files:
|
|
45
|
+
1. First check if `node_modules/@pure-ds/core/` exists (consuming project)
|
|
46
|
+
2. Otherwise use workspace root paths (pure-ds development)
|
|
47
|
+
3. Prefer reading actual files over guessing - the data is authoritative
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## π pds-form Best Practices
|
|
52
|
+
|
|
53
|
+
**When generating pds-form code, ALWAYS follow these patterns:**
|
|
54
|
+
|
|
55
|
+
### 1. Event Handling - Use `pw:submit`, NOT `submit`
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
// β
CORRECT: Listen to pw:submit custom event
|
|
59
|
+
form.addEventListener('pw:submit', async (e) => {
|
|
60
|
+
const { json, formData, valid, issues } = e.detail;
|
|
61
|
+
if (valid) {
|
|
62
|
+
// Handle submission with json or formData
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// β WRONG: Native submit event
|
|
67
|
+
form.addEventListener('submit', (e) => { /* Won't work */ });
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 2. Submit Button Progress - Add `btn-working` automatically
|
|
71
|
+
|
|
72
|
+
**When user requests a form with async submission, ALWAYS:**
|
|
73
|
+
- Add `btn-working` class to submit button during processing
|
|
74
|
+
- Remove it when done (PDS automatically shows spinner icon)
|
|
75
|
+
- Use a realistic 2-3 second delay for demos
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
// β
CORRECT: Auto-add progress state
|
|
79
|
+
form.addEventListener('pw:submit', async (e) => {
|
|
80
|
+
const submitBtn = form.querySelector('button[type="submit"]');
|
|
81
|
+
submitBtn?.classList.add('btn-working');
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
await simulateSubmit(e.detail.json); // 2-3 second promise
|
|
85
|
+
await PDS.toast('Submitted successfully!', { type: 'success' });
|
|
86
|
+
} finally {
|
|
87
|
+
submitBtn?.classList.remove('btn-working');
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
async function simulateSubmit(data) {
|
|
92
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
93
|
+
console.log('Submitted:', data);
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 3. Progressive Enhancement - Add `data-required` to form wrapper
|
|
98
|
+
|
|
99
|
+
```html
|
|
100
|
+
<!-- β
CORRECT: Wrap pds-form in form[data-required] -->
|
|
101
|
+
<form data-required>
|
|
102
|
+
<pds-form id="myForm" hide-actions></pds-form>
|
|
103
|
+
<div class="form-actions">
|
|
104
|
+
<button type="submit" class="btn-primary">Submit</button>
|
|
105
|
+
</div>
|
|
106
|
+
</form>
|
|
107
|
+
|
|
108
|
+
<!-- β WRONG: No data-required enhancement -->
|
|
109
|
+
<pds-form id="myForm"></pds-form>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### 4. JSON Schema - Use `examples` for placeholders
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
// β
CORRECT: Use examples array for placeholders
|
|
116
|
+
const schema = {
|
|
117
|
+
type: "object",
|
|
118
|
+
properties: {
|
|
119
|
+
name: {
|
|
120
|
+
type: "string",
|
|
121
|
+
title: "Full Name",
|
|
122
|
+
examples: ["John Doe"] // First example becomes placeholder
|
|
123
|
+
},
|
|
124
|
+
email: {
|
|
125
|
+
type: "string",
|
|
126
|
+
format: "email",
|
|
127
|
+
title: "Email",
|
|
128
|
+
examples: ["user@example.com"]
|
|
129
|
+
},
|
|
130
|
+
age: {
|
|
131
|
+
type: "integer",
|
|
132
|
+
title: "Age",
|
|
133
|
+
examples: [25] // Works for numbers too
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// β WRONG: No placeholders or using wrong property
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 5. UI Schema - Infer smart icons automatically
|
|
142
|
+
|
|
143
|
+
**Common field β icon mappings (use these by default):**
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
const smartIcons = {
|
|
147
|
+
email: 'envelope',
|
|
148
|
+
phone: 'phone',
|
|
149
|
+
name: 'user',
|
|
150
|
+
password: 'lock',
|
|
151
|
+
search: 'search',
|
|
152
|
+
message: 'message',
|
|
153
|
+
comment: 'comment',
|
|
154
|
+
address: 'map-marker',
|
|
155
|
+
website: 'link',
|
|
156
|
+
date: 'calendar',
|
|
157
|
+
time: 'clock',
|
|
158
|
+
subject: 'tag',
|
|
159
|
+
priority: 'flag',
|
|
160
|
+
category: 'folder',
|
|
161
|
+
file: 'file',
|
|
162
|
+
image: 'image'
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const uiSchema = {
|
|
166
|
+
email: {
|
|
167
|
+
'ui:widget': 'email',
|
|
168
|
+
'ui:placeholder': 'user@example.com',
|
|
169
|
+
'ui:icon': 'envelope', // Auto-infer
|
|
170
|
+
'ui:autocomplete': 'email'
|
|
171
|
+
},
|
|
172
|
+
phone: {
|
|
173
|
+
'ui:widget': 'tel',
|
|
174
|
+
'ui:icon': 'phone',
|
|
175
|
+
'ui:autocomplete': 'tel'
|
|
176
|
+
},
|
|
177
|
+
message: {
|
|
178
|
+
'ui:widget': 'textarea',
|
|
179
|
+
'ui:rows': 4,
|
|
180
|
+
'ui:icon': 'message'
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### 6. Complete Working Example
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
// Schema with examples for placeholders
|
|
189
|
+
const contactSchema = {
|
|
190
|
+
type: "object",
|
|
191
|
+
required: ["name", "email", "message"],
|
|
192
|
+
properties: {
|
|
193
|
+
name: {
|
|
194
|
+
type: "string",
|
|
195
|
+
title: "Name",
|
|
196
|
+
minLength: 2,
|
|
197
|
+
examples: ["John Doe"]
|
|
198
|
+
},
|
|
199
|
+
email: {
|
|
200
|
+
type: "string",
|
|
201
|
+
format: "email",
|
|
202
|
+
title: "Email",
|
|
203
|
+
examples: ["user@example.com"]
|
|
204
|
+
},
|
|
205
|
+
message: {
|
|
206
|
+
type: "string",
|
|
207
|
+
title: "Message",
|
|
208
|
+
minLength: 10,
|
|
209
|
+
examples: ["Your message here..."]
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
// UI schema with smart icons
|
|
215
|
+
const uiSchema = {
|
|
216
|
+
name: { 'ui:icon': 'user' },
|
|
217
|
+
email: { 'ui:icon': 'envelope' },
|
|
218
|
+
message: {
|
|
219
|
+
'ui:widget': 'textarea',
|
|
220
|
+
'ui:rows': 4,
|
|
221
|
+
'ui:icon': 'message'
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// Setup with pw:submit and btn-working
|
|
226
|
+
const form = document.getElementById('contactForm');
|
|
227
|
+
form.jsonSchema = contactSchema;
|
|
228
|
+
form.uiSchema = uiSchema;
|
|
229
|
+
|
|
230
|
+
form.addEventListener('pw:submit', async (e) => {
|
|
231
|
+
const submitBtn = form.querySelector('button[type="submit"]');
|
|
232
|
+
submitBtn?.classList.add('btn-working');
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
// Simulate 2s async operation
|
|
236
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
237
|
+
console.log('Submitted:', e.detail.json);
|
|
238
|
+
await PDS.toast('Message sent!', { type: 'success' });
|
|
239
|
+
form.reset();
|
|
240
|
+
} catch (error) {
|
|
241
|
+
await PDS.toast('Failed to send', { type: 'error' });
|
|
242
|
+
} finally {
|
|
243
|
+
submitBtn?.classList.remove('btn-working');
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
44
248
|
---
|
|
45
249
|
|
|
46
250
|
## π« Critical Anti-Patterns (NEVER DO THIS)
|
|
@@ -61,12 +265,72 @@ PDS follows the [Pure Web Manifesto](https://pureweb.dev/manifesto): "The browse
|
|
|
61
265
|
|
|
62
266
|
```javascript
|
|
63
267
|
// β NEVER: Browser dialogs - Use PDS.ask() and PDS.toast()
|
|
64
|
-
alert("message"); // β PDS.toast("message", { type: "info" })
|
|
268
|
+
alert("message"); // β await PDS.toast("message", { type: "info" })
|
|
65
269
|
confirm("sure?"); // β await PDS.ask("sure?", { type: "confirm" })
|
|
66
270
|
prompt("name?"); // β await PDS.ask("name?", { type: "prompt" })
|
|
67
271
|
|
|
68
272
|
// β NEVER: Manual dropdown/modal/tab implementations
|
|
69
273
|
// β Use <nav data-dropdown>, PDS.ask(), <pds-tabstrip>
|
|
274
|
+
|
|
275
|
+
// β NEVER: Access lazy-loaded component APIs before they're defined
|
|
276
|
+
const form = document.querySelector('pds-form');
|
|
277
|
+
form.getFormData(); // May fail - component not loaded yet
|
|
278
|
+
|
|
279
|
+
// β NEVER: Use native 'submit' event with pds-form
|
|
280
|
+
form.addEventListener('submit', (e) => { }); // β Use 'pw:submit'
|
|
281
|
+
|
|
282
|
+
// β NEVER: Forget btn-working class for async operations
|
|
283
|
+
button.onclick = async () => {
|
|
284
|
+
await fetch('/api'); // No loading indicator!
|
|
285
|
+
};
|
|
286
|
+
// β Add button.classList.add('btn-working') before, remove after
|
|
287
|
+
|
|
288
|
+
// β NEVER: Hardcode placeholders instead of using schema examples
|
|
289
|
+
const schema = {
|
|
290
|
+
properties: {
|
|
291
|
+
email: { type: "string" } // Missing examples!
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
// β Add examples: ["user@example.com"]
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## β‘ Lit Components & Import Maps
|
|
300
|
+
|
|
301
|
+
**Components that require Lit:** `pds-form`
|
|
302
|
+
|
|
303
|
+
This component uses `import { ... } from "#pds/lit"` and **requires** an import map:
|
|
304
|
+
|
|
305
|
+
```html
|
|
306
|
+
<!-- REQUIRED in HTML <head> for Lit components -->
|
|
307
|
+
<script type="importmap">
|
|
308
|
+
{
|
|
309
|
+
"imports": {
|
|
310
|
+
"#pds/lit": "/assets/js/lit.js"
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
</script>
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
**When generating code with lazy-loaded components, ALWAYS wait for definition:**
|
|
317
|
+
|
|
318
|
+
```javascript
|
|
319
|
+
// β
CORRECT: Wait for component to load
|
|
320
|
+
await customElements.whenDefined('pds-form');
|
|
321
|
+
const form = document.querySelector('pds-form');
|
|
322
|
+
form.getFormData(); // Safe
|
|
323
|
+
|
|
324
|
+
// β
CORRECT: Alternative pattern
|
|
325
|
+
const FormClass = await customElements.get('pds-form');
|
|
326
|
+
if (FormClass) {
|
|
327
|
+
const form = document.createElement('pds-form');
|
|
328
|
+
// ...
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// β WRONG: Direct access without waiting
|
|
332
|
+
const form = document.querySelector('pds-form');
|
|
333
|
+
form.getFormData(); // May throw error
|
|
70
334
|
```
|
|
71
335
|
|
|
72
336
|
---
|
|
@@ -130,7 +394,7 @@ const confirmed = await PDS.ask("Delete this item?", {
|
|
|
130
394
|
buttons: { ok: { name: "Delete", variant: "danger" } }
|
|
131
395
|
});
|
|
132
396
|
|
|
133
|
-
PDS.toast("Saved successfully!", { type: "success" });
|
|
397
|
+
await PDS.toast("Saved successfully!", { type: "success" });
|
|
134
398
|
|
|
135
399
|
// Theme management
|
|
136
400
|
PDS.theme = 'dark'; // 'light' | 'dark' | 'system'
|
|
@@ -141,6 +405,20 @@ const results = await PDS.query("border gradient classes");
|
|
|
141
405
|
|
|
142
406
|
---
|
|
143
407
|
|
|
408
|
+
## π Additional Resources
|
|
409
|
+
|
|
410
|
+
**For comprehensive pds-form documentation:**
|
|
411
|
+
- Read [pds-form-docs.md](../pds-form-docs.md) for complete API reference
|
|
412
|
+
- See [packages/pds-storybook/stories/components/PdsForm.stories.js](../packages/pds-storybook/stories/components/PdsForm.stories.js) for real examples
|
|
413
|
+
- Check [custom-elements.json](../custom-elements.json) for component API details
|
|
414
|
+
|
|
415
|
+
**For toast notifications:**
|
|
416
|
+
- Use `PDS.toast()` method (see [src/js/common/toast.js](../src/js/common/toast.js) for implementation)
|
|
417
|
+
- Automatically ensures pds-toaster exists and is loaded before displaying
|
|
418
|
+
- See pds-toaster component API in [custom-elements.json](../custom-elements.json)
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
144
422
|
## How to Look Things Up
|
|
145
423
|
|
|
146
424
|
| Question | Action |
|
|
@@ -166,3 +444,13 @@ Before generating code:
|
|
|
166
444
|
6. β
**Apply enhancements via data-* attributes** β See `pds-enhancer-metadata.js`
|
|
167
445
|
7. β
**Components as last resort** β Only when native HTML can't achieve it
|
|
168
446
|
8. β
**Prefer primitives** β `.card`, `.badge`, `.alert` over custom components
|
|
447
|
+
9. β
**Wait for lazy components** β Use `await customElements.whenDefined()` before accessing APIs
|
|
448
|
+
10. β
**Include import map** β When using `pds-form` or `pds-drawer`, ensure `#pds/lit` is mapped
|
|
449
|
+
|
|
450
|
+
**For pds-form specifically:**
|
|
451
|
+
|
|
452
|
+
11. β
**Use `pw:submit` event** β NOT native `submit` event
|
|
453
|
+
12. β
**Add `btn-working` class** β For async submit operations, add during processing
|
|
454
|
+
13. β
**Use `examples` in JSON schema** β First example becomes placeholder
|
|
455
|
+
14. β
**Add smart icons** β Infer icons based on field names (emailβenvelope, phoneβphone)
|
|
456
|
+
15. β
**Wrap in `form[data-required]`** β For asterisk enhancement on required fields
|