@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 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