@pure-ds/core 0.4.25 → 0.4.27
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 +180 -86
- package/.github/copilot-instructions.md +134 -80
- package/dist/types/pds.d.ts +470 -109
- 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/src/js/pds-core/pds-enhancers.d.ts +14 -0
- package/dist/types/src/js/pds-core/pds-enhancers.d.ts.map +1 -1
- package/package.json +1 -1
- package/packages/pds-cli/bin/pds-setup-copilot.js +1 -1
- package/packages/pds-cli/bin/pds-static.js +27 -2
- package/public/assets/js/app.js +45 -45
- package/public/assets/js/pds.js +19 -19
- package/public/assets/pds/custom-elements.json +168 -164
- package/src/js/pds-core/pds-enhancers.js +136 -3
- package/src/js/pds.js +7 -1
- package/src/js/pds-core/pds-enhancer-metadata.js +0 -96
package/.cursorrules
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# PDS (Pure Design System) -
|
|
1
|
+
# PDS (Pure Design System) - AI Generation Instructions
|
|
2
2
|
|
|
3
|
-
> **CRITICAL**: This workspace uses **Pure Design System (PDS)**. All code generation MUST follow PDS patterns. Never use
|
|
3
|
+
> **CRITICAL**: This workspace uses **Pure Design System (PDS)**. All code generation MUST follow PDS and vanilla Web Platform patterns. Never use 3rd party framework patterns, non-PDS utility classes, inline styles, or hardcoded CSS values.
|
|
4
4
|
|
|
5
5
|
## Philosophy
|
|
6
6
|
|
|
@@ -31,7 +31,7 @@ PDS follows the [Pure Web Manifesto](https://pureweb.dev/manifesto): "The browse
|
|
|
31
31
|
| **Web Components** | `custom-elements.json` | Complete component APIs, attributes, methods, events, slots |
|
|
32
32
|
| **HTML Tags** | `public/assets/pds/vscode-custom-data.json` | Component HTML structure, attribute values |
|
|
33
33
|
| **Primitives & Utilities** | `src/js/pds-core/pds-ontology.js` | `.card`, `.badge`, `.btn-*`, `.flex`, `.gap-*`, `.surface-*` |
|
|
34
|
-
| **Enhancements** | `src/js/pds-core/pds-
|
|
34
|
+
| **Enhancements** | `src/js/pds-core/pds-enhancers.js` | Enhancement metadata (`defaultPDSEnhancerMetadata`) + runtime (`defaultPDSEnhancers`) |
|
|
35
35
|
| **Generator Logic** | `src/js/pds-core/pds-generator.js` | How CSS is generated, token naming conventions |
|
|
36
36
|
| **Config** | `pds.config.js` | What's enabled in this workspace |
|
|
37
37
|
|
|
@@ -94,95 +94,147 @@ async function simulateSubmit(data) {
|
|
|
94
94
|
}
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
### 3.
|
|
97
|
+
### 3. Adding `data-required` to pds-form generated form: simply add the attribute to the pds-form tag
|
|
98
98
|
|
|
99
99
|
```html
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
100
|
+
<pds-form data-required id="myForm" hide-actions></pds-form>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 4. Placeholders - ALWAYS include examples
|
|
104
|
+
|
|
105
|
+
**Placeholders improve UX significantly. Try to add 'examples' array to schema properties:**
|
|
106
|
+
|
|
107
|
+
**Rule: When generating a form, infer appropriate placeholders based on field name/type if not specified.**
|
|
107
108
|
|
|
108
|
-
|
|
109
|
-
|
|
109
|
+
### 5. Smart Icons - Infer from field semantics
|
|
110
|
+
|
|
111
|
+
**When generating forms, automatically add appropriate icons based on field names and semantics.**
|
|
112
|
+
|
|
113
|
+
**Sources of truth for available icons:**
|
|
114
|
+
- Check `pds.config.js` for project-specific icon configuration
|
|
115
|
+
- Consult icon sprite at `public/assets/img/icons/pds-icons.svg` for available icons
|
|
116
|
+
- See `public/assets/pds/vscode-custom-data.json` for icon attribute values
|
|
117
|
+
|
|
118
|
+
**Use semantic reasoning to match field names to appropriate icons:**
|
|
119
|
+
|
|
120
|
+
```javascript
|
|
121
|
+
// ✅ CORRECT: Infer icons based on field semantics
|
|
122
|
+
const uiSchema = {
|
|
123
|
+
"/email": { 'ui:icon': 'envelope', 'ui:autocomplete': 'email' },
|
|
124
|
+
"/phone": { 'ui:icon': 'phone', 'ui:autocomplete': 'tel' },
|
|
125
|
+
"/name": { 'ui:icon': 'user', 'ui:autocomplete': 'name' },
|
|
126
|
+
"/password": { 'ui:icon': 'lock', 'ui:widget': 'password' },
|
|
127
|
+
"/website": { 'ui:icon': 'link' },
|
|
128
|
+
"/address": { 'ui:icon': 'map-pin' },
|
|
129
|
+
"/date": { 'ui:icon': 'calendar' },
|
|
130
|
+
"/message": { 'ui:widget': 'textarea', 'ui:icon': 'message' }
|
|
131
|
+
};
|
|
110
132
|
```
|
|
111
133
|
|
|
112
|
-
|
|
134
|
+
**Rule: When generating forms, analyze field names/types and select semantically appropriate icons from the available icon set.**
|
|
135
|
+
|
|
136
|
+
### 6. Submit Handler Pattern - ALWAYS provide working async handler
|
|
137
|
+
|
|
138
|
+
**When generating a pds-form, ALWAYS include a complete, iteration-ready submit handler with:**
|
|
139
|
+
- `pw:submit` event (NOT native submit)
|
|
140
|
+
- `btn-working` class for loading state
|
|
141
|
+
- `PDS.toast()` for user feedback
|
|
142
|
+
- Error handling
|
|
143
|
+
- Realistic async simulation
|
|
113
144
|
|
|
114
145
|
```javascript
|
|
115
|
-
// ✅ CORRECT:
|
|
116
|
-
|
|
117
|
-
type
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
146
|
+
// ✅ CORRECT: Complete submit handler pattern
|
|
147
|
+
form.addEventListener('pw:submit', async (e) => {
|
|
148
|
+
const submitBtn = form.querySelector('button[type="submit"]');
|
|
149
|
+
submitBtn?.classList.add('btn-working');
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
// Simulate async operation (replace with real API call)
|
|
153
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
154
|
+
|
|
155
|
+
// Log the data for debugging
|
|
156
|
+
console.log('Submitted data:', e.detail.json);
|
|
157
|
+
|
|
158
|
+
// Show success toast
|
|
159
|
+
await PDS.toast('Form submitted successfully!', { type: 'success' });
|
|
160
|
+
|
|
161
|
+
// Optionally reset form
|
|
162
|
+
form.reset();
|
|
163
|
+
} catch (error) {
|
|
164
|
+
// Show error toast
|
|
165
|
+
await PDS.toast('Submission failed: ' + error.message, { type: 'error' });
|
|
166
|
+
} finally {
|
|
167
|
+
// Always remove loading state
|
|
168
|
+
submitBtn?.classList.remove('btn-working');
|
|
135
169
|
}
|
|
136
|
-
};
|
|
170
|
+
});
|
|
137
171
|
|
|
138
|
-
// ❌ WRONG:
|
|
172
|
+
// ❌ WRONG: Native submit event
|
|
173
|
+
form.addEventListener('submit', (e) => { /* Won't work */ });
|
|
174
|
+
|
|
175
|
+
// ❌ WRONG: No loading state
|
|
176
|
+
form.addEventListener('pw:submit', async (e) => {
|
|
177
|
+
await fetch('/api'); // No visual feedback!
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// ❌ WRONG: Browser dialogs
|
|
181
|
+
form.addEventListener('pw:submit', async (e) => {
|
|
182
|
+
alert('Submitted!'); // Use PDS.toast() instead
|
|
183
|
+
});
|
|
139
184
|
```
|
|
140
185
|
|
|
141
|
-
|
|
186
|
+
**PDS.toast() is available globally via window.PDS:**
|
|
187
|
+
|
|
188
|
+
```javascript
|
|
189
|
+
// All toast types
|
|
190
|
+
await PDS.toast('Success message', { type: 'success' });
|
|
191
|
+
await PDS.toast('Error occurred', { type: 'error' });
|
|
192
|
+
await PDS.toast('Warning message', { type: 'warning' });
|
|
193
|
+
await PDS.toast('Info message', { type: 'information' });
|
|
142
194
|
|
|
143
|
-
|
|
195
|
+
// Custom duration (auto-calculated by default based on message length)
|
|
196
|
+
await PDS.toast('Quick message', { type: 'info', duration: 3000 });
|
|
197
|
+
|
|
198
|
+
// Persistent (requires manual close)
|
|
199
|
+
await PDS.toast('Important notice', { type: 'warning', persistent: true });
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### 7. Conditional "Other" Fields - Auto-generate ui:visibleWhen
|
|
203
|
+
|
|
204
|
+
**When a schema has an "Other" enum option, ALWAYS auto-generate a conditional text field:**
|
|
144
205
|
|
|
145
206
|
```javascript
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
207
|
+
const schema = {
|
|
208
|
+
type: "object",
|
|
209
|
+
properties: {
|
|
210
|
+
reason: {
|
|
211
|
+
type: "string",
|
|
212
|
+
title: "How did you hear about us?",
|
|
213
|
+
oneOf: [
|
|
214
|
+
{ const: "search", title: "Search Engine" },
|
|
215
|
+
{ const: "social", title: "Social Media" },
|
|
216
|
+
{ const: "friend", title: "Friend Referral" },
|
|
217
|
+
{ const: "other", title: "Other... (please specify)" }, // ← "Other" option
|
|
218
|
+
],
|
|
219
|
+
},
|
|
220
|
+
otherReason: { // ← Conditional field for "Other"
|
|
221
|
+
type: "string",
|
|
222
|
+
title: "Please specify",
|
|
223
|
+
examples: ["Tell us more..."],
|
|
224
|
+
},
|
|
225
|
+
},
|
|
163
226
|
};
|
|
164
227
|
|
|
165
228
|
const uiSchema = {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
'ui:autocomplete': 'email'
|
|
171
|
-
},
|
|
172
|
-
phone: {
|
|
173
|
-
'ui:widget': 'tel',
|
|
174
|
-
'ui:icon': 'phone',
|
|
175
|
-
'ui:autocomplete': 'tel'
|
|
229
|
+
// ✅ ALWAYS add these when "other" enum exists
|
|
230
|
+
"/otherReason": {
|
|
231
|
+
"ui:visibleWhen": { "/reason": "other" },
|
|
232
|
+
"ui:requiredWhen": { "/reason": "other" },
|
|
176
233
|
},
|
|
177
|
-
message: {
|
|
178
|
-
'ui:widget': 'textarea',
|
|
179
|
-
'ui:rows': 4,
|
|
180
|
-
'ui:icon': 'message'
|
|
181
|
-
}
|
|
182
234
|
};
|
|
183
235
|
```
|
|
184
236
|
|
|
185
|
-
###
|
|
237
|
+
### 8. Complete Working Example
|
|
186
238
|
|
|
187
239
|
```javascript
|
|
188
240
|
// Schema with examples for placeholders
|
|
@@ -213,9 +265,9 @@ const contactSchema = {
|
|
|
213
265
|
|
|
214
266
|
// UI schema with smart icons
|
|
215
267
|
const uiSchema = {
|
|
216
|
-
name: { 'ui:icon': 'user' },
|
|
217
|
-
email: { 'ui:icon': 'envelope' },
|
|
218
|
-
message: {
|
|
268
|
+
"/name": { 'ui:icon': 'user' },
|
|
269
|
+
"/email": { 'ui:icon': 'envelope' },
|
|
270
|
+
"/message": {
|
|
219
271
|
'ui:widget': 'textarea',
|
|
220
272
|
'ui:rows': 4,
|
|
221
273
|
'ui:icon': 'message'
|
|
@@ -296,6 +348,45 @@ const schema = {
|
|
|
296
348
|
|
|
297
349
|
---
|
|
298
350
|
|
|
351
|
+
## ⚡ Lit Components & Import Maps
|
|
352
|
+
|
|
353
|
+
**Components that require Lit:** `pds-form`
|
|
354
|
+
|
|
355
|
+
This component uses `import { ... } from "#pds/lit"` and **requires** an import map:
|
|
356
|
+
|
|
357
|
+
```html
|
|
358
|
+
<!-- REQUIRED in HTML <head> for Lit components -->
|
|
359
|
+
<script type="importmap">
|
|
360
|
+
{
|
|
361
|
+
"imports": {
|
|
362
|
+
"#pds/lit": "/assets/js/lit.js"
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
</script>
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**When generating code with lazy-loaded components, ALWAYS wait for definition:**
|
|
369
|
+
|
|
370
|
+
```javascript
|
|
371
|
+
// ✅ CORRECT: Wait for component to load
|
|
372
|
+
await customElements.whenDefined('pds-form');
|
|
373
|
+
const form = document.querySelector('pds-form');
|
|
374
|
+
form.getFormData(); // Safe
|
|
375
|
+
|
|
376
|
+
// ✅ CORRECT: Alternative pattern
|
|
377
|
+
const FormClass = await customElements.get('pds-form');
|
|
378
|
+
if (FormClass) {
|
|
379
|
+
const form = document.createElement('pds-form');
|
|
380
|
+
// ...
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// ❌ WRONG: Direct access without waiting
|
|
384
|
+
const form = document.querySelector('pds-form');
|
|
385
|
+
form.getFormData(); // May throw error
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
299
390
|
## ✅ Quick Reference Patterns
|
|
300
391
|
|
|
301
392
|
```html
|
|
@@ -324,7 +415,7 @@ const schema = {
|
|
|
324
415
|
<pds-icon icon="heart" size="sm"></pds-icon>
|
|
325
416
|
<pds-icon icon="check" size="lg" color="var(--color-success-500)"></pds-icon>
|
|
326
417
|
|
|
327
|
-
<!-- Enhancements: data attributes (see pds-
|
|
418
|
+
<!-- Enhancements: data attributes (see pds-enhancers.js → defaultPDSEnhancerMetadata) -->
|
|
328
419
|
<nav data-dropdown>
|
|
329
420
|
<button>Menu</button>
|
|
330
421
|
<menu><li><a href="#">Item</a></li></menu>
|
|
@@ -341,10 +432,12 @@ const schema = {
|
|
|
341
432
|
|
|
342
433
|
<!-- Tabs: web component -->
|
|
343
434
|
<pds-tabstrip>
|
|
344
|
-
<
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
<
|
|
435
|
+
<pds-tabpanel label="Tab 1">
|
|
436
|
+
<p>Content for Tab 1</p>
|
|
437
|
+
</pds-tabpanel>
|
|
438
|
+
<pds-tabpanel label="Tab 2">
|
|
439
|
+
<p>Content for Tab 2</p>
|
|
440
|
+
</pds-tabpanel>
|
|
348
441
|
</pds-tabstrip>
|
|
349
442
|
```
|
|
350
443
|
|
|
@@ -369,14 +462,15 @@ const results = await PDS.query("border gradient classes");
|
|
|
369
462
|
## 📚 Additional Resources
|
|
370
463
|
|
|
371
464
|
**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
|
|
465
|
+
- Read [pds-form-docs.md](../pds-form-docs.md) for complete API reference
|
|
466
|
+
- See [packages/pds-storybook/stories/components/PdsForm.stories.js](../packages/pds-storybook/stories/components/PdsForm.stories.js) for real examples
|
|
467
|
+
- Check [custom-elements.json](../custom-elements.json) for component API details
|
|
375
468
|
|
|
376
469
|
**For toast notifications:**
|
|
377
|
-
- Use `PDS.toast()` method (see [src/js/common/toast.js](src/js/common/toast.js) for implementation)
|
|
470
|
+
- Use `PDS.toast()` method (see [src/js/common/toast.js](../src/js/common/toast.js) for implementation)
|
|
378
471
|
- Automatically ensures pds-toaster exists and is loaded before displaying
|
|
379
|
-
- See pds-toaster component API in [custom-elements.json](custom-elements.json)
|
|
472
|
+
- See pds-toaster component API in [custom-elements.json](../custom-elements.json)
|
|
473
|
+
|
|
380
474
|
---
|
|
381
475
|
|
|
382
476
|
## How to Look Things Up
|
|
@@ -387,7 +481,7 @@ const results = await PDS.query("border gradient classes");
|
|
|
387
481
|
| "What components are available?" | Read `custom-elements.json` |
|
|
388
482
|
| "What utility classes exist?" | Read `pds-ontology.js` → `layoutPatterns`, `utilities` |
|
|
389
483
|
| "What primitives exist?" | Read `pds-ontology.js` → `primitives` |
|
|
390
|
-
| "How do I enhance HTML?" | Read `pds-
|
|
484
|
+
| "How do I enhance HTML?" | Read `pds-enhancers.js` → `defaultPDSEnhancerMetadata` → `demoHtml` |
|
|
391
485
|
| "How are tokens named?" | Read `pds-generator.js` or `pds.css-data.json` |
|
|
392
486
|
|
|
393
487
|
---
|
|
@@ -401,7 +495,7 @@ Before generating code:
|
|
|
401
495
|
3. ✅ **No hardcoded values** — Colors, spacing, radii all have tokens
|
|
402
496
|
4. ✅ **No alert/confirm/prompt** — Use `PDS.ask()` and `PDS.toast()`
|
|
403
497
|
5. ✅ **Use semantic HTML** — `<button>`, `<nav>`, `<article>`, `<label>`, `<details>`
|
|
404
|
-
6. ✅ **Apply enhancements via data-* attributes** — See `pds-
|
|
498
|
+
6. ✅ **Apply enhancements via data-* attributes** — See `pds-enhancers.js` → `defaultPDSEnhancerMetadata`
|
|
405
499
|
7. ✅ **Components as last resort** — Only when native HTML can't achieve it
|
|
406
500
|
8. ✅ **Prefer primitives** — `.card`, `.badge`, `.alert` over custom components
|
|
407
501
|
9. ✅ **Wait for lazy components** — Use `await customElements.whenDefined()` before accessing APIs
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# PDS (Pure Design System) -
|
|
1
|
+
# PDS (Pure Design System) - AI Generation Instructions
|
|
2
2
|
|
|
3
3
|
> **CRITICAL**: This workspace uses **Pure Design System (PDS)**. All code generation MUST follow PDS and vanilla Web Platform patterns. Never use 3rd party framework patterns, non-PDS utility classes, inline styles, or hardcoded CSS values.
|
|
4
4
|
|
|
@@ -31,7 +31,7 @@ PDS follows the [Pure Web Manifesto](https://pureweb.dev/manifesto): "The browse
|
|
|
31
31
|
| **Web Components** | `custom-elements.json` | Complete component APIs, attributes, methods, events, slots |
|
|
32
32
|
| **HTML Tags** | `public/assets/pds/vscode-custom-data.json` | Component HTML structure, attribute values |
|
|
33
33
|
| **Primitives & Utilities** | `src/js/pds-core/pds-ontology.js` | `.card`, `.badge`, `.btn-*`, `.flex`, `.gap-*`, `.surface-*` |
|
|
34
|
-
| **Enhancements** | `src/js/pds-core/pds-
|
|
34
|
+
| **Enhancements** | `src/js/pds-core/pds-enhancers.js` | Enhancement metadata (`defaultPDSEnhancerMetadata`) + runtime (`defaultPDSEnhancers`) |
|
|
35
35
|
| **Generator Logic** | `src/js/pds-core/pds-generator.js` | How CSS is generated, token naming conventions |
|
|
36
36
|
| **Config** | `pds.config.js` | What's enabled in this workspace |
|
|
37
37
|
|
|
@@ -94,95 +94,147 @@ async function simulateSubmit(data) {
|
|
|
94
94
|
}
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
### 3.
|
|
97
|
+
### 3. Adding `data-required` to pds-form generated form: simply add the attribute to the pds-form tag
|
|
98
98
|
|
|
99
99
|
```html
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
100
|
+
<pds-form data-required id="myForm" hide-actions></pds-form>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 4. Placeholders - ALWAYS include examples
|
|
104
|
+
|
|
105
|
+
**Placeholders improve UX significantly. Try to add 'examples' array to schema properties:**
|
|
106
|
+
|
|
107
|
+
**Rule: When generating a form, infer appropriate placeholders based on field name/type if not specified.**
|
|
108
|
+
|
|
109
|
+
### 5. Smart Icons - Infer from field semantics
|
|
110
|
+
|
|
111
|
+
**When generating forms, automatically add appropriate icons based on field names and semantics.**
|
|
112
|
+
|
|
113
|
+
**Sources of truth for available icons:**
|
|
114
|
+
- Check `pds.config.js` for project-specific icon configuration
|
|
115
|
+
- Consult icon sprite at `public/assets/img/icons/pds-icons.svg` for available icons
|
|
116
|
+
- See `public/assets/pds/vscode-custom-data.json` for icon attribute values
|
|
107
117
|
|
|
108
|
-
|
|
109
|
-
|
|
118
|
+
**Use semantic reasoning to match field names to appropriate icons:**
|
|
119
|
+
|
|
120
|
+
```javascript
|
|
121
|
+
// ✅ CORRECT: Infer icons based on field semantics
|
|
122
|
+
const uiSchema = {
|
|
123
|
+
"/email": { 'ui:icon': 'envelope', 'ui:autocomplete': 'email' },
|
|
124
|
+
"/phone": { 'ui:icon': 'phone', 'ui:autocomplete': 'tel' },
|
|
125
|
+
"/name": { 'ui:icon': 'user', 'ui:autocomplete': 'name' },
|
|
126
|
+
"/password": { 'ui:icon': 'lock', 'ui:widget': 'password' },
|
|
127
|
+
"/website": { 'ui:icon': 'link' },
|
|
128
|
+
"/address": { 'ui:icon': 'map-pin' },
|
|
129
|
+
"/date": { 'ui:icon': 'calendar' },
|
|
130
|
+
"/message": { 'ui:widget': 'textarea', 'ui:icon': 'message' }
|
|
131
|
+
};
|
|
110
132
|
```
|
|
111
133
|
|
|
112
|
-
|
|
134
|
+
**Rule: When generating forms, analyze field names/types and select semantically appropriate icons from the available icon set.**
|
|
135
|
+
|
|
136
|
+
### 6. Submit Handler Pattern - ALWAYS provide working async handler
|
|
137
|
+
|
|
138
|
+
**When generating a pds-form, ALWAYS include a complete, iteration-ready submit handler with:**
|
|
139
|
+
- `pw:submit` event (NOT native submit)
|
|
140
|
+
- `btn-working` class for loading state
|
|
141
|
+
- `PDS.toast()` for user feedback
|
|
142
|
+
- Error handling
|
|
143
|
+
- Realistic async simulation
|
|
113
144
|
|
|
114
145
|
```javascript
|
|
115
|
-
// ✅ CORRECT:
|
|
116
|
-
|
|
117
|
-
type
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
146
|
+
// ✅ CORRECT: Complete submit handler pattern
|
|
147
|
+
form.addEventListener('pw:submit', async (e) => {
|
|
148
|
+
const submitBtn = form.querySelector('button[type="submit"]');
|
|
149
|
+
submitBtn?.classList.add('btn-working');
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
// Simulate async operation (replace with real API call)
|
|
153
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
154
|
+
|
|
155
|
+
// Log the data for debugging
|
|
156
|
+
console.log('Submitted data:', e.detail.json);
|
|
157
|
+
|
|
158
|
+
// Show success toast
|
|
159
|
+
await PDS.toast('Form submitted successfully!', { type: 'success' });
|
|
160
|
+
|
|
161
|
+
// Optionally reset form
|
|
162
|
+
form.reset();
|
|
163
|
+
} catch (error) {
|
|
164
|
+
// Show error toast
|
|
165
|
+
await PDS.toast('Submission failed: ' + error.message, { type: 'error' });
|
|
166
|
+
} finally {
|
|
167
|
+
// Always remove loading state
|
|
168
|
+
submitBtn?.classList.remove('btn-working');
|
|
135
169
|
}
|
|
136
|
-
};
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// ❌ WRONG: Native submit event
|
|
173
|
+
form.addEventListener('submit', (e) => { /* Won't work */ });
|
|
137
174
|
|
|
138
|
-
// ❌ WRONG: No
|
|
175
|
+
// ❌ WRONG: No loading state
|
|
176
|
+
form.addEventListener('pw:submit', async (e) => {
|
|
177
|
+
await fetch('/api'); // No visual feedback!
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// ❌ WRONG: Browser dialogs
|
|
181
|
+
form.addEventListener('pw:submit', async (e) => {
|
|
182
|
+
alert('Submitted!'); // Use PDS.toast() instead
|
|
183
|
+
});
|
|
139
184
|
```
|
|
140
185
|
|
|
141
|
-
|
|
186
|
+
**PDS.toast() is available globally via window.PDS:**
|
|
187
|
+
|
|
188
|
+
```javascript
|
|
189
|
+
// All toast types
|
|
190
|
+
await PDS.toast('Success message', { type: 'success' });
|
|
191
|
+
await PDS.toast('Error occurred', { type: 'error' });
|
|
192
|
+
await PDS.toast('Warning message', { type: 'warning' });
|
|
193
|
+
await PDS.toast('Info message', { type: 'information' });
|
|
142
194
|
|
|
143
|
-
|
|
195
|
+
// Custom duration (auto-calculated by default based on message length)
|
|
196
|
+
await PDS.toast('Quick message', { type: 'info', duration: 3000 });
|
|
197
|
+
|
|
198
|
+
// Persistent (requires manual close)
|
|
199
|
+
await PDS.toast('Important notice', { type: 'warning', persistent: true });
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### 7. Conditional "Other" Fields - Auto-generate ui:visibleWhen
|
|
203
|
+
|
|
204
|
+
**When a schema has an "Other" enum option, ALWAYS auto-generate a conditional text field:**
|
|
144
205
|
|
|
145
206
|
```javascript
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
207
|
+
const schema = {
|
|
208
|
+
type: "object",
|
|
209
|
+
properties: {
|
|
210
|
+
reason: {
|
|
211
|
+
type: "string",
|
|
212
|
+
title: "How did you hear about us?",
|
|
213
|
+
oneOf: [
|
|
214
|
+
{ const: "search", title: "Search Engine" },
|
|
215
|
+
{ const: "social", title: "Social Media" },
|
|
216
|
+
{ const: "friend", title: "Friend Referral" },
|
|
217
|
+
{ const: "other", title: "Other... (please specify)" }, // ← "Other" option
|
|
218
|
+
],
|
|
219
|
+
},
|
|
220
|
+
otherReason: { // ← Conditional field for "Other"
|
|
221
|
+
type: "string",
|
|
222
|
+
title: "Please specify",
|
|
223
|
+
examples: ["Tell us more..."],
|
|
224
|
+
},
|
|
225
|
+
},
|
|
163
226
|
};
|
|
164
227
|
|
|
165
228
|
const uiSchema = {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
'ui:autocomplete': 'email'
|
|
171
|
-
},
|
|
172
|
-
phone: {
|
|
173
|
-
'ui:widget': 'tel',
|
|
174
|
-
'ui:icon': 'phone',
|
|
175
|
-
'ui:autocomplete': 'tel'
|
|
229
|
+
// ✅ ALWAYS add these when "other" enum exists
|
|
230
|
+
"/otherReason": {
|
|
231
|
+
"ui:visibleWhen": { "/reason": "other" },
|
|
232
|
+
"ui:requiredWhen": { "/reason": "other" },
|
|
176
233
|
},
|
|
177
|
-
message: {
|
|
178
|
-
'ui:widget': 'textarea',
|
|
179
|
-
'ui:rows': 4,
|
|
180
|
-
'ui:icon': 'message'
|
|
181
|
-
}
|
|
182
234
|
};
|
|
183
235
|
```
|
|
184
236
|
|
|
185
|
-
###
|
|
237
|
+
### 8. Complete Working Example
|
|
186
238
|
|
|
187
239
|
```javascript
|
|
188
240
|
// Schema with examples for placeholders
|
|
@@ -213,9 +265,9 @@ const contactSchema = {
|
|
|
213
265
|
|
|
214
266
|
// UI schema with smart icons
|
|
215
267
|
const uiSchema = {
|
|
216
|
-
name: { 'ui:icon': 'user' },
|
|
217
|
-
email: { 'ui:icon': 'envelope' },
|
|
218
|
-
message: {
|
|
268
|
+
"/name": { 'ui:icon': 'user' },
|
|
269
|
+
"/email": { 'ui:icon': 'envelope' },
|
|
270
|
+
"/message": {
|
|
219
271
|
'ui:widget': 'textarea',
|
|
220
272
|
'ui:rows': 4,
|
|
221
273
|
'ui:icon': 'message'
|
|
@@ -363,7 +415,7 @@ form.getFormData(); // May throw error
|
|
|
363
415
|
<pds-icon icon="heart" size="sm"></pds-icon>
|
|
364
416
|
<pds-icon icon="check" size="lg" color="var(--color-success-500)"></pds-icon>
|
|
365
417
|
|
|
366
|
-
<!-- Enhancements: data attributes (see pds-
|
|
418
|
+
<!-- Enhancements: data attributes (see pds-enhancers.js → defaultPDSEnhancerMetadata) -->
|
|
367
419
|
<nav data-dropdown>
|
|
368
420
|
<button>Menu</button>
|
|
369
421
|
<menu><li><a href="#">Item</a></li></menu>
|
|
@@ -380,10 +432,12 @@ form.getFormData(); // May throw error
|
|
|
380
432
|
|
|
381
433
|
<!-- Tabs: web component -->
|
|
382
434
|
<pds-tabstrip>
|
|
383
|
-
<
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
<
|
|
435
|
+
<pds-tabpanel label="Tab 1">
|
|
436
|
+
<p>Content for Tab 1</p>
|
|
437
|
+
</pds-tabpanel>
|
|
438
|
+
<pds-tabpanel label="Tab 2">
|
|
439
|
+
<p>Content for Tab 2</p>
|
|
440
|
+
</pds-tabpanel>
|
|
387
441
|
</pds-tabstrip>
|
|
388
442
|
```
|
|
389
443
|
|
|
@@ -427,7 +481,7 @@ const results = await PDS.query("border gradient classes");
|
|
|
427
481
|
| "What components are available?" | Read `custom-elements.json` |
|
|
428
482
|
| "What utility classes exist?" | Read `pds-ontology.js` → `layoutPatterns`, `utilities` |
|
|
429
483
|
| "What primitives exist?" | Read `pds-ontology.js` → `primitives` |
|
|
430
|
-
| "How do I enhance HTML?" | Read `pds-
|
|
484
|
+
| "How do I enhance HTML?" | Read `pds-enhancers.js` → `defaultPDSEnhancerMetadata` → `demoHtml` |
|
|
431
485
|
| "How are tokens named?" | Read `pds-generator.js` or `pds.css-data.json` |
|
|
432
486
|
|
|
433
487
|
---
|
|
@@ -441,7 +495,7 @@ Before generating code:
|
|
|
441
495
|
3. ✅ **No hardcoded values** — Colors, spacing, radii all have tokens
|
|
442
496
|
4. ✅ **No alert/confirm/prompt** — Use `PDS.ask()` and `PDS.toast()`
|
|
443
497
|
5. ✅ **Use semantic HTML** — `<button>`, `<nav>`, `<article>`, `<label>`, `<details>`
|
|
444
|
-
6. ✅ **Apply enhancements via data-* attributes** — See `pds-
|
|
498
|
+
6. ✅ **Apply enhancements via data-* attributes** — See `pds-enhancers.js` → `defaultPDSEnhancerMetadata`
|
|
445
499
|
7. ✅ **Components as last resort** — Only when native HTML can't achieve it
|
|
446
500
|
8. ✅ **Prefer primitives** — `.card`, `.badge`, `.alert` over custom components
|
|
447
501
|
9. ✅ **Wait for lazy components** — Use `await customElements.whenDefined()` before accessing APIs
|