@pure-ds/core 0.7.57 → 0.7.58
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 +63 -589
- package/.github/copilot-instructions.md +63 -598
- package/custom-elements.json +110 -5
- package/dist/types/pds.d.ts +65 -0
- package/dist/types/src/js/common/common.d.ts +7 -0
- package/dist/types/src/js/common/common.d.ts.map +1 -1
- package/dist/types/src/js/pds-autocomplete.d.ts +74 -1
- package/dist/types/src/js/pds-autocomplete.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-start-helpers.d.ts.map +1 -1
- package/dist/types/src/js/pds-reactive.d.ts +101 -0
- package/dist/types/src/js/pds-reactive.d.ts.map +1 -0
- package/dist/types/src/js/pds.d.ts +4 -1
- package/dist/types/src/js/pds.d.ts.map +1 -1
- package/package.json +1 -2
- package/packages/pds-cli/lib/pds-mcp-core.js +436 -1
- package/public/assets/js/app.js +7 -6
- package/public/assets/js/pds-ask.js +4 -4
- package/public/assets/js/pds-autocomplete.js +7 -7
- package/public/assets/js/pds-manager.js +144 -143
- package/public/assets/js/pds.js +3 -2
- package/public/assets/pds/core/pds-ask.js +4 -4
- package/public/assets/pds/core/pds-autocomplete.js +7 -7
- package/public/assets/pds/core/pds-manager.js +144 -143
- package/public/assets/pds/core.js +3 -2
- package/public/assets/pds/custom-elements.json +382 -28
- package/public/assets/pds/pds-css-complete.json +1 -1
- package/public/assets/pds/vscode-custom-data.json +29 -1
- package/src/js/common/common.js +74 -0
- package/src/js/pds-core/pds-start-helpers.js +17 -2
- package/src/js/pds.d.ts +65 -0
- package/src/js/pds.js +13 -0
package/.cursorrules
CHANGED
|
@@ -1,627 +1,101 @@
|
|
|
1
|
-
# PDS (Pure Design System)
|
|
1
|
+
# PDS (Pure Design System) — AI 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
|
|
|
5
|
-
> **CRITICAL — Unless
|
|
5
|
+
> **CRITICAL — Unless in the pure-ds origin project, `/pds/` PATHS ARE READ-ONLY**: Files under `public/pds/**`, `public/assets/pds/**`, and `node_modules/@pure-ds/core/public/**` are immutable package output. To change behavior, edit source (`src/js/pds-core/**`, `pds.config.js`) then rebuild.
|
|
6
6
|
|
|
7
|
-
> **Note:
|
|
7
|
+
> **Note: In the pure-ds (@pure-ds/core origin) project itself**, `pds-*` web components in `pds/components/` ARE their own source — not compiled from elsewhere.
|
|
8
|
+
|
|
9
|
+
---
|
|
8
10
|
|
|
9
11
|
## Philosophy
|
|
10
12
|
|
|
11
13
|
PDS follows the [Pure Web Manifesto](https://pureweb.dev/manifesto): "The browser is the framework."
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
> Note: all (lazy loaded) PDS web components are rolled out to consuming projects in their [public root]/assets/pds/components/ folder, and are never provided as source that needs to be bundled. The web component scripts are copied there at npm install time (postinstall), and are ready to be used because the PDS AutoDefiner will define them when added to the DOM.
|
|
19
|
-
|
|
20
|
-
### The Four Layers
|
|
21
|
-
|
|
22
|
-
**Layer 1 — Styles**: From minimal config, PDS generates complete CSS: tokens, scales, semantics, surfaces, states. Zero specificity via `:where()`.
|
|
15
|
+
- **Standards-first**: Web Platform APIs only (no framework dependencies)
|
|
16
|
+
- **Configuration-driven**: `pds.config.js` generates all CSS (tokens, scales, semantics, surfaces, states). Zero specificity via `:where()`.
|
|
17
|
+
- **Progressive Enhancement**: Semantic HTML first, enhance where needed
|
|
18
|
+
- **Layers**: 1 — Styles/tokens → 2 — Enhancements (`data-*`) → 3 — Web Components (`pds-*`) → 4 — LLM Support
|
|
23
19
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
**Layer 3 — Web Components**: `<pds-tabstrip>`, `<pds-drawer>`, etc. only when native HTML has no equivalent.
|
|
27
|
-
|
|
28
|
-
**Layer 4: LLM Support**: Install `@pure-ds/core` and get instant PDS AI Coding Instrucions at your fingertips (GitHub Copilot & Cursor support built in)
|
|
20
|
+
> PDS web components are lazy-loaded from `[public-root]/assets/pds/components/` — never bundled by the consuming project. The PDS AutoDefiner registers them when added to the DOM.
|
|
29
21
|
|
|
30
22
|
---
|
|
31
23
|
|
|
32
|
-
##
|
|
33
|
-
|
|
34
|
-
**Before generating code, read the relevant SSoT file to get accurate class names, tokens, and APIs.**
|
|
35
|
-
|
|
36
|
-
| Need | SSoT File | What It Contains |
|
|
37
|
-
|------|-----------|------------------|
|
|
38
|
-
| **CSS Tokens** | `public/assets/pds/pds.css-data.json` | All `--color-*`, `--spacing-*`, `--radius-*`, `--shadow-*`, `--font-*` |
|
|
39
|
-
| **Web Components** | `custom-elements.json` | Complete component APIs, attributes, methods, events, slots |
|
|
40
|
-
| **HTML Tags** | `public/assets/pds/vscode-custom-data.json` | Component HTML structure, attribute values |
|
|
41
|
-
| **Primitives & Utilities** | `src/js/pds-core/pds-ontology.js` | `.card`, `.badge`, `.btn-*`, `.flex`, `.gap-*`, `.surface-*` |
|
|
42
|
-
| **Enhancements** | `src/js/pds-core/pds-enhancers.js` | Enhancement metadata (`defaultPDSEnhancerMetadata`) + runtime (`defaultPDSEnhancers`) |
|
|
43
|
-
| **Generator Logic** | `src/js/pds-core/pds-generator.js` | How CSS is generated, token naming conventions |
|
|
44
|
-
| **Config (Runtime)** | `pds.config.js` | What's enabled in this workspace |
|
|
45
|
-
| **Config (SSoT)** | `src/js/pds-core/pds-config.js` | JSDoc types + validation spec + `PDS_CONFIG_RELATIONS` for deterministic token mapping |
|
|
46
|
-
|
|
47
|
-
**For consuming projects** using `@pure-ds/core`, files are in `node_modules/@pure-ds/core/`:
|
|
48
|
-
- `custom-elements.json`
|
|
49
|
-
- `public/assets/pds/pds.css-data.json`
|
|
50
|
-
- `public/assets/pds/vscode-custom-data.json`
|
|
51
|
-
- `src/js/pds-core/pds-ontology.js`
|
|
52
|
-
|
|
53
|
-
**Path resolution helper:** When looking up SSoT files:
|
|
54
|
-
1. First check if `node_modules/@pure-ds/core/` exists (consuming project)
|
|
55
|
-
2. Otherwise use workspace root paths (pure-ds development)
|
|
56
|
-
3. Prefer reading actual files over guessing - the data is authoritative
|
|
57
|
-
|
|
58
|
-
## 🔌 MCP Lookup Protocol (Optional)
|
|
59
|
-
|
|
60
|
-
Use MCP as an optimization, not a prerequisite. For fast, simple lookups, read local SSoT files directly first.
|
|
61
|
-
|
|
62
|
-
### When MCP is already connected
|
|
63
|
-
|
|
64
|
-
1. **Tokens** → call `get_tokens`
|
|
65
|
-
2. **Primitives / utilities / selectors** → call `find_utility_class`
|
|
66
|
-
3. **Natural-language DS search** → call `query_design_system`
|
|
67
|
-
4. **Web component API** → call `get_component_api`
|
|
68
|
-
5. **Enhancer metadata + demoHtml** → call `get_enhancer_metadata`
|
|
69
|
-
6. **Design config deterministic mapping** → call `get_config_relations`
|
|
70
|
-
7. **Final snippet sanity check** → call `validate_pds_snippet`
|
|
71
|
-
|
|
72
|
-
### Non-negotiable rules
|
|
73
|
-
|
|
74
|
-
- Do not invent class names, tokens, attributes, events, or selectors.
|
|
75
|
-
- If a value is not found in MCP results, state it is unavailable and suggest nearest matches.
|
|
76
|
-
- Prefer MCP results over memory when MCP is already available.
|
|
77
|
-
- If MCP is unavailable, slow to start, or errors, continue immediately with direct SSoT file reads using the paths above.
|
|
78
|
-
- Never block or fail an answer solely because MCP is unavailable.
|
|
79
|
-
- If neither MCP nor file reads are available, provide only conservative guidance and clearly mark uncertainty.
|
|
24
|
+
## Single Sources of Truth
|
|
80
25
|
|
|
81
|
-
|
|
26
|
+
> In consuming projects, prefix paths with `node_modules/@pure-ds/core/`.
|
|
82
27
|
|
|
83
|
-
|
|
28
|
+
| Need | SSoT File |
|
|
29
|
+
|------|-----------|
|
|
30
|
+
| CSS Tokens | `public/assets/pds/pds.css-data.json` |
|
|
31
|
+
| Web Component APIs | `custom-elements.json` |
|
|
32
|
+
| HTML tags & attributes | `public/assets/pds/vscode-custom-data.json` |
|
|
33
|
+
| Primitives & Utilities | `src/js/pds-core/pds-ontology.js` |
|
|
34
|
+
| Enhancement metadata | `src/js/pds-core/pds-enhancers.js` |
|
|
35
|
+
| Config types & token relations | `src/js/pds-core/pds-config.js` |
|
|
84
36
|
|
|
85
|
-
|
|
86
|
-
- Do **not** inspect or modify specialized components (e.g., `pds-form`) unless the user explicitly asks for that component or the failing code is clearly inside that component.
|
|
87
|
-
- Start from the smallest relevant layer: **Layer 1 (styles/utilities)** → **Layer 2 (enhancers)** → **Layer 3 (web components)** only if needed.
|
|
88
|
-
- For consuming projects, prefer usage-level fixes in app markup/classes before proposing framework/core changes.
|
|
37
|
+
**Prefer reading these files over guessing class names or token names.**
|
|
89
38
|
|
|
90
39
|
---
|
|
91
40
|
|
|
92
|
-
##
|
|
93
|
-
|
|
94
|
-
**When generating pds-form code, ALWAYS follow these patterns:**
|
|
95
|
-
|
|
96
|
-
### 1. Event Handling - Use `pw:submit`, NOT `submit`
|
|
97
|
-
|
|
98
|
-
```javascript
|
|
99
|
-
// ✅ CORRECT: Listen to pw:submit custom event
|
|
100
|
-
form.addEventListener('pw:submit', async (e) => {
|
|
101
|
-
const { json, formData, valid, issues } = e.detail;
|
|
102
|
-
if (valid) {
|
|
103
|
-
// Handle submission with json or formData
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// ❌ WRONG: Native submit event
|
|
108
|
-
form.addEventListener('submit', (e) => { /* Won't work */ });
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
### 2. Submit Button Progress - Add `btn-working` automatically
|
|
112
|
-
|
|
113
|
-
**When user requests a form with async submission, ALWAYS:**
|
|
114
|
-
- Add `btn-working` class to submit button during processing
|
|
115
|
-
- Remove it when done (PDS automatically shows spinner icon)
|
|
116
|
-
- Use a realistic 2-3 second delay for demos
|
|
117
|
-
|
|
118
|
-
```javascript
|
|
119
|
-
// ✅ CORRECT: Auto-add progress state
|
|
120
|
-
form.addEventListener('pw:submit', async (e) => {
|
|
121
|
-
const submitBtn = form.querySelector('button[type="submit"]');
|
|
122
|
-
submitBtn?.classList.add('btn-working');
|
|
123
|
-
|
|
124
|
-
try {
|
|
125
|
-
await simulateSubmit(e.detail.json); // 2-3 second promise
|
|
126
|
-
await PDS.toast('Submitted successfully!', { type: 'success' });
|
|
127
|
-
} finally {
|
|
128
|
-
submitBtn?.classList.remove('btn-working');
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
async function simulateSubmit(data) {
|
|
133
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
134
|
-
console.log('Submitted:', data);
|
|
135
|
-
}
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
### 3. Adding `data-required` to pds-form generated form: simply add the attribute to the pds-form tag
|
|
139
|
-
|
|
140
|
-
```html
|
|
141
|
-
<pds-form data-required id="myForm" hide-actions></pds-form>
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### 4. Placeholders - ALWAYS include examples
|
|
145
|
-
|
|
146
|
-
**Placeholders improve UX significantly. Try to add 'examples' array to schema properties:**
|
|
147
|
-
|
|
148
|
-
**Rule: When generating a form, infer appropriate placeholders based on field name/type if not specified.**
|
|
149
|
-
|
|
150
|
-
### 5. Smart Icons - Infer from field semantics
|
|
151
|
-
|
|
152
|
-
**When generating forms, automatically add appropriate icons based on field names and semantics.**
|
|
153
|
-
|
|
154
|
-
**Sources of truth for available icons:**
|
|
155
|
-
- Check `pds.config.js` for project-specific icon configuration
|
|
156
|
-
- Consult icon sprite at `public/assets/img/icons/pds-icons.svg` for available icons
|
|
157
|
-
- See `public/assets/pds/vscode-custom-data.json` for icon attribute values
|
|
158
|
-
|
|
159
|
-
**Use semantic reasoning to match field names to appropriate icons:**
|
|
160
|
-
|
|
161
|
-
```javascript
|
|
162
|
-
// ✅ CORRECT: Infer icons based on field semantics
|
|
163
|
-
const uiSchema = {
|
|
164
|
-
"/email": { 'ui:icon': 'envelope', 'ui:autocomplete': 'email' },
|
|
165
|
-
"/phone": { 'ui:icon': 'phone', 'ui:autocomplete': 'tel' },
|
|
166
|
-
"/name": { 'ui:icon': 'user', 'ui:autocomplete': 'name' },
|
|
167
|
-
"/password": { 'ui:icon': 'lock', 'ui:widget': 'password' },
|
|
168
|
-
"/website": { 'ui:icon': 'link' },
|
|
169
|
-
"/address": { 'ui:icon': 'map-pin' },
|
|
170
|
-
"/date": { 'ui:icon': 'calendar' },
|
|
171
|
-
"/message": { 'ui:widget': 'textarea', 'ui:icon': 'message' }
|
|
172
|
-
};
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
**Rule: When generating forms, analyze field names/types and select semantically appropriate icons from the available icon set.**
|
|
176
|
-
|
|
177
|
-
### 6. Submit Handler Pattern - ALWAYS provide working async handler
|
|
178
|
-
|
|
179
|
-
**When generating a pds-form, ALWAYS include a complete, iteration-ready submit handler with:**
|
|
180
|
-
- `pw:submit` event (NOT native submit)
|
|
181
|
-
- `btn-working` class for loading state
|
|
182
|
-
- `PDS.toast()` for user feedback
|
|
183
|
-
- Error handling
|
|
184
|
-
- Realistic async simulation
|
|
185
|
-
|
|
186
|
-
```javascript
|
|
187
|
-
// ✅ CORRECT: Complete submit handler pattern
|
|
188
|
-
form.addEventListener('pw:submit', async (e) => {
|
|
189
|
-
const submitBtn = form.querySelector('button[type="submit"]');
|
|
190
|
-
submitBtn?.classList.add('btn-working');
|
|
191
|
-
|
|
192
|
-
try {
|
|
193
|
-
// Simulate async operation (replace with real API call)
|
|
194
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
195
|
-
|
|
196
|
-
// Log the data for debugging
|
|
197
|
-
console.log('Submitted data:', e.detail.json);
|
|
198
|
-
|
|
199
|
-
// Show success toast
|
|
200
|
-
await PDS.toast('Form submitted successfully!', { type: 'success' });
|
|
201
|
-
|
|
202
|
-
// Optionally reset form
|
|
203
|
-
form.reset();
|
|
204
|
-
} catch (error) {
|
|
205
|
-
// Show error toast
|
|
206
|
-
await PDS.toast('Submission failed: ' + error.message, { type: 'error' });
|
|
207
|
-
} finally {
|
|
208
|
-
// Always remove loading state
|
|
209
|
-
submitBtn?.classList.remove('btn-working');
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
// ❌ WRONG: Native submit event
|
|
214
|
-
form.addEventListener('submit', (e) => { /* Won't work */ });
|
|
215
|
-
|
|
216
|
-
// ❌ WRONG: No loading state
|
|
217
|
-
form.addEventListener('pw:submit', async (e) => {
|
|
218
|
-
await fetch('/api'); // No visual feedback!
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
// ❌ WRONG: Browser dialogs
|
|
222
|
-
form.addEventListener('pw:submit', async (e) => {
|
|
223
|
-
alert('Submitted!'); // Use PDS.toast() instead
|
|
224
|
-
});
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
**PDS.toast() is available from the imported `PDS` runtime:**
|
|
228
|
-
|
|
229
|
-
```javascript
|
|
230
|
-
import { PDS } from '#pds';
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
```javascript
|
|
234
|
-
// All toast types
|
|
235
|
-
await PDS.toast('Success message', { type: 'success' });
|
|
236
|
-
await PDS.toast('Error occurred', { type: 'error' });
|
|
237
|
-
await PDS.toast('Warning message', { type: 'warning' });
|
|
238
|
-
await PDS.toast('Info message', { type: 'information' });
|
|
239
|
-
|
|
240
|
-
// Custom duration (auto-calculated by default based on message length)
|
|
241
|
-
await PDS.toast('Quick message', { type: 'info', duration: 3000 });
|
|
242
|
-
|
|
243
|
-
// Persistent (requires manual close)
|
|
244
|
-
await PDS.toast('Important notice', { type: 'warning', persistent: true });
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
### 7. Conditional "Other" Fields - Auto-generate ui:visibleWhen
|
|
248
|
-
|
|
249
|
-
**When a schema has an "Other" enum option, ALWAYS auto-generate a conditional text field:**
|
|
250
|
-
|
|
251
|
-
```javascript
|
|
252
|
-
const schema = {
|
|
253
|
-
type: "object",
|
|
254
|
-
properties: {
|
|
255
|
-
reason: {
|
|
256
|
-
type: "string",
|
|
257
|
-
title: "How did you hear about us?",
|
|
258
|
-
oneOf: [
|
|
259
|
-
{ const: "search", title: "Search Engine" },
|
|
260
|
-
{ const: "social", title: "Social Media" },
|
|
261
|
-
{ const: "friend", title: "Friend Referral" },
|
|
262
|
-
{ const: "other", title: "Other... (please specify)" }, // ← "Other" option
|
|
263
|
-
],
|
|
264
|
-
},
|
|
265
|
-
otherReason: { // ← Conditional field for "Other"
|
|
266
|
-
type: "string",
|
|
267
|
-
title: "Please specify",
|
|
268
|
-
examples: ["Tell us more..."],
|
|
269
|
-
},
|
|
270
|
-
},
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
const uiSchema = {
|
|
274
|
-
// ✅ ALWAYS add these when "other" enum exists
|
|
275
|
-
"/otherReason": {
|
|
276
|
-
"ui:visibleWhen": { "/reason": "other" },
|
|
277
|
-
"ui:requiredWhen": { "/reason": "other" },
|
|
278
|
-
},
|
|
279
|
-
};
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
### 8. Complete Working Example
|
|
283
|
-
|
|
284
|
-
```javascript
|
|
285
|
-
// Schema with examples for placeholders
|
|
286
|
-
const contactSchema = {
|
|
287
|
-
type: "object",
|
|
288
|
-
required: ["name", "email", "message"],
|
|
289
|
-
properties: {
|
|
290
|
-
name: {
|
|
291
|
-
type: "string",
|
|
292
|
-
title: "Name",
|
|
293
|
-
minLength: 2,
|
|
294
|
-
examples: ["John Doe"]
|
|
295
|
-
},
|
|
296
|
-
email: {
|
|
297
|
-
type: "string",
|
|
298
|
-
format: "email",
|
|
299
|
-
title: "Email",
|
|
300
|
-
examples: ["user@example.com"]
|
|
301
|
-
},
|
|
302
|
-
message: {
|
|
303
|
-
type: "string",
|
|
304
|
-
title: "Message",
|
|
305
|
-
minLength: 10,
|
|
306
|
-
examples: ["Your message here..."]
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
};
|
|
310
|
-
|
|
311
|
-
// UI schema with smart icons
|
|
312
|
-
const uiSchema = {
|
|
313
|
-
"/name": { 'ui:icon': 'user' },
|
|
314
|
-
"/email": { 'ui:icon': 'envelope' },
|
|
315
|
-
"/message": {
|
|
316
|
-
'ui:widget': 'textarea',
|
|
317
|
-
'ui:rows': 4,
|
|
318
|
-
'ui:icon': 'message'
|
|
319
|
-
}
|
|
320
|
-
};
|
|
321
|
-
|
|
322
|
-
// Setup with pw:submit and btn-working
|
|
323
|
-
const form = document.getElementById('contactForm');
|
|
324
|
-
form.jsonSchema = contactSchema;
|
|
325
|
-
form.uiSchema = uiSchema;
|
|
326
|
-
|
|
327
|
-
form.addEventListener('pw:submit', async (e) => {
|
|
328
|
-
const submitBtn = form.querySelector('button[type="submit"]');
|
|
329
|
-
submitBtn?.classList.add('btn-working');
|
|
330
|
-
|
|
331
|
-
try {
|
|
332
|
-
// Simulate 2s async operation
|
|
333
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
334
|
-
console.log('Submitted:', e.detail.json);
|
|
335
|
-
await PDS.toast('Message sent!', { type: 'success' });
|
|
336
|
-
form.reset();
|
|
337
|
-
} catch (error) {
|
|
338
|
-
await PDS.toast('Failed to send', { type: 'error' });
|
|
339
|
-
} finally {
|
|
340
|
-
submitBtn?.classList.remove('btn-working');
|
|
341
|
-
}
|
|
342
|
-
});
|
|
343
|
-
```
|
|
41
|
+
## 🔌 MCP Lookup Protocol — MANDATORY
|
|
344
42
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
## 🚫 Critical Anti-Patterns (NEVER DO THIS)
|
|
348
|
-
|
|
349
|
-
```html
|
|
350
|
-
<!-- ❌ NEVER: Inline styles -->
|
|
351
|
-
<div style="display: flex; gap: 16px; padding: 20px;">
|
|
352
|
-
|
|
353
|
-
<!-- ❌ NEVER: Hardcoded colors -->
|
|
354
|
-
<button style="background: #007acc; color: white;">
|
|
355
|
-
|
|
356
|
-
<!-- ❌ NEVER: Non-semantic HTML -->
|
|
357
|
-
<div class="button" onclick="handleClick()">Click me</div>
|
|
358
|
-
|
|
359
|
-
<!-- ❌ NEVER: Custom CSS when primitives exist -->
|
|
360
|
-
<style>.my-card { border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }</style>
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
```javascript
|
|
364
|
-
// ❌ NEVER: Browser dialogs - Use PDS.ask() and PDS.toast()
|
|
365
|
-
alert("message"); // → await PDS.toast("message", { type: "info" })
|
|
366
|
-
confirm("sure?"); // → await PDS.ask("sure?", { type: "confirm" })
|
|
367
|
-
prompt("name?"); // → await PDS.ask("name?", { type: "prompt" })
|
|
368
|
-
|
|
369
|
-
// ❌ NEVER: Manual dropdown/modal/tab implementations
|
|
370
|
-
// → Use <nav data-dropdown>, PDS.ask(), <pds-tabstrip>
|
|
43
|
+
**Before generating any PDS code, call the relevant MCP tool(s) first. Never invent class names, tokens, attributes, or component APIs.**
|
|
371
44
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
45
|
+
| Topic | MCP Tool |
|
|
46
|
+
|-------|----------|
|
|
47
|
+
| CSS tokens (`--color-*`, `--spacing-*`, etc.) | `get_tokens` |
|
|
48
|
+
| Buttons, cards, layout, surfaces, utilities | `find_utility_class` |
|
|
49
|
+
| Any `pds-*` component | `get_component_api` |
|
|
50
|
+
| Any `data-*` enhancement | `get_enhancer_metadata` |
|
|
51
|
+
| Forms, localization, DOM building, toasts, treeview | `query_design_system("your question")` |
|
|
52
|
+
| Config / token naming rules | `get_config_relations` |
|
|
53
|
+
| After generating HTML | `validate_pds_snippet` |
|
|
375
54
|
|
|
376
|
-
|
|
377
|
-
form.addEventListener('submit', (e) => { }); // → Use 'pw:submit'
|
|
55
|
+
**`query_design_system` auto-injects best-practice guidance with code examples** based on your question. Use it for: pds-form patterns, submit handlers, localization, `parse`/`html` DOM building, `PDS.toast`/`PDS.ask`, treeview lazy loading, Lit import maps, empty states, and more.
|
|
378
56
|
|
|
379
|
-
|
|
380
|
-
button.onclick = async () => {
|
|
381
|
-
await fetch('/api'); // No loading indicator!
|
|
382
|
-
};
|
|
383
|
-
// → Add button.classList.add('btn-working') before, remove after
|
|
384
|
-
|
|
385
|
-
// ❌ NEVER: Hardcode placeholders instead of using schema examples
|
|
386
|
-
const schema = {
|
|
387
|
-
properties: {
|
|
388
|
-
email: { type: "string" } // Missing examples!
|
|
389
|
-
}
|
|
390
|
-
};
|
|
391
|
-
// → Add examples: ["user@example.com"]
|
|
392
|
-
```
|
|
393
|
-
|
|
394
|
-
---
|
|
395
|
-
|
|
396
|
-
## ⚡ Lit Components & Import Maps
|
|
397
|
-
|
|
398
|
-
**Components that require Lit:** `pds-form`
|
|
399
|
-
|
|
400
|
-
This component uses `import { ... } from "#pds/lit"` and **requires** an import map:
|
|
401
|
-
|
|
402
|
-
```html
|
|
403
|
-
<!-- REQUIRED in HTML <head> for Lit components -->
|
|
404
|
-
<script type="importmap">
|
|
405
|
-
{
|
|
406
|
-
"imports": {
|
|
407
|
-
"#pds": "/assets/pds/core.js",
|
|
408
|
-
"#pds/lit": "/assets/pds/external/lit.js"
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
</script>
|
|
412
|
-
```
|
|
413
|
-
|
|
414
|
-
**Note:** `#pds/lit` is a convenience bundle that re-exports Lit and adds PDS helpers (`lazyProps`, `msg()`, `loadLocale()`). If a project prefers its own Lit bundle, it must provide equivalents and map `#pds/lit` accordingly.
|
|
415
|
-
|
|
416
|
-
**When generating code with lazy-loaded components, ALWAYS wait for definition:**
|
|
417
|
-
|
|
418
|
-
```javascript
|
|
419
|
-
// ✅ CORRECT: Wait for component to load
|
|
420
|
-
await customElements.whenDefined('pds-form');
|
|
421
|
-
const form = document.querySelector('pds-form');
|
|
422
|
-
form.getFormData(); // Safe
|
|
423
|
-
|
|
424
|
-
// In a Lit context, use the lazyProps directive (included in #pds/lit bundle)
|
|
425
|
-
<pds-fab
|
|
426
|
-
id="fab-three"
|
|
427
|
-
${lazyProps({ satellites })}
|
|
428
|
-
>
|
|
429
|
-
<pds-icon icon="plus" size="lg" data-original-icon="plus"></pds-icon>
|
|
430
|
-
</pds-fab>
|
|
431
|
-
|
|
432
|
-
// ✅ CORRECT: Alternative pattern
|
|
433
|
-
const FormClass = await customElements.get('pds-form');
|
|
434
|
-
if (FormClass) {
|
|
435
|
-
const form = document.createElement('pds-form');
|
|
436
|
-
// ...
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
// ❌ WRONG: Direct access without waiting
|
|
440
|
-
const form = document.querySelector('pds-form');
|
|
441
|
-
form.getFormData(); // May throw error
|
|
442
|
-
```
|
|
57
|
+
**If MCP is unavailable**: fall back to reading SSoT files directly. Never block on MCP.
|
|
443
58
|
|
|
444
59
|
---
|
|
445
60
|
|
|
446
|
-
##
|
|
447
|
-
|
|
448
|
-
```html
|
|
449
|
-
<!-- Buttons: semantic HTML + PDS classes (see pds-ontology.js → primitives) -->
|
|
450
|
-
<button class="btn-primary">Save</button>
|
|
451
|
-
<button class="btn-secondary">Cancel</button>
|
|
452
|
-
<button class="btn-outline">Details</button>
|
|
453
|
-
<button class="btn-primary icon-only" aria-label="Settings">
|
|
454
|
-
<pds-icon icon="gear"></pds-icon>
|
|
455
|
-
</button>
|
|
456
|
-
|
|
457
|
-
<!-- Layout: utility classes (see pds-ontology.js → layoutPatterns, utilities) -->
|
|
458
|
-
<div class="flex gap-md items-center">
|
|
459
|
-
<div class="grid grid-cols-3 gap-lg">
|
|
460
|
-
<div class="stack-md">
|
|
461
|
-
|
|
462
|
-
<!-- Cards & Surfaces: primitives -->
|
|
463
|
-
<article class="card surface-elevated">
|
|
464
|
-
<header class="flex justify-between items-center">
|
|
465
|
-
<h3>Title</h3>
|
|
466
|
-
</header>
|
|
467
|
-
<p class="text-muted">Content</p>
|
|
468
|
-
</article>
|
|
469
|
-
|
|
470
|
-
<!-- Icons: web component (see custom-elements.json) -->
|
|
471
|
-
<pds-icon icon="heart" size="sm"></pds-icon>
|
|
472
|
-
<pds-icon icon="check" size="lg" color="var(--color-success-500)"></pds-icon>
|
|
473
|
-
|
|
474
|
-
<!-- Enhancements: data attributes (see pds-enhancers.js → defaultPDSEnhancerMetadata) -->
|
|
475
|
-
<nav data-dropdown>
|
|
476
|
-
<button>Menu</button>
|
|
477
|
-
<menu><li><a href="#">Item</a></li></menu>
|
|
478
|
-
</nav>
|
|
479
|
-
|
|
480
|
-
<label data-toggle>
|
|
481
|
-
<input type="checkbox">
|
|
482
|
-
<span data-label>Enable feature</span>
|
|
483
|
-
</label>
|
|
484
|
-
|
|
485
|
-
<!-- Treeview: lazy node loading -->
|
|
486
|
-
<pds-treeview id="docsTree"></pds-treeview>
|
|
487
|
-
|
|
488
|
-
<script type="module">
|
|
489
|
-
const tree = document.getElementById('docsTree');
|
|
490
|
-
tree.options = {
|
|
491
|
-
// Initial payload can be shallow (e.g., 2 levels)
|
|
492
|
-
source: [
|
|
493
|
-
{
|
|
494
|
-
id: 'docs',
|
|
495
|
-
text: 'Docs',
|
|
496
|
-
hasChildren: true,
|
|
497
|
-
children: [
|
|
498
|
-
{ id: 'guides', text: 'Guides', hasChildren: true },
|
|
499
|
-
{ id: 'components', text: 'Components', hasChildren: true }
|
|
500
|
-
]
|
|
501
|
-
}
|
|
502
|
-
],
|
|
503
|
-
// Fetch children only when a node is expanded
|
|
504
|
-
getChildren: async ({ nodeId }) => {
|
|
505
|
-
const res = await fetch(`/api/tree?parent=${encodeURIComponent(nodeId)}`);
|
|
506
|
-
return res.ok ? res.json() : [];
|
|
507
|
-
}
|
|
508
|
-
};
|
|
509
|
-
</script>
|
|
510
|
-
|
|
511
|
-
**Treeview lazy-loading rules:**
|
|
512
|
-
- Mark expandable nodes with `hasChildren: true` when children are not yet included in the initial `source`.
|
|
513
|
-
- Provide `options.getChildren({ node, nodeId, host, options, settings })` for node-level fetch on first expand.
|
|
514
|
-
- Prefer shallow initial payloads (root + immediate children), then fetch deeper levels as users expand.
|
|
515
|
-
- Use `node-load` and `node-load-error` events for telemetry, loading UX, and retries.
|
|
516
|
-
|
|
517
|
-
<form data-required>
|
|
518
|
-
<label><span>Email</span><input type="email" required></label>
|
|
519
|
-
</form>
|
|
520
|
-
|
|
521
|
-
<!-- Tabs: web component -->
|
|
522
|
-
<pds-tabstrip>
|
|
523
|
-
<pds-tabpanel label="Tab 1">
|
|
524
|
-
<p>Content for Tab 1</p>
|
|
525
|
-
</pds-tabpanel>
|
|
526
|
-
<pds-tabpanel label="Tab 2">
|
|
527
|
-
<p>Content for Tab 2</p>
|
|
528
|
-
</pds-tabpanel>
|
|
529
|
-
</pds-tabstrip>
|
|
530
|
-
|
|
531
|
-
<!-- Details: wrap post-summary content in a padded primitive -->
|
|
532
|
-
<details>
|
|
533
|
-
<summary>Section title</summary>
|
|
534
|
-
<div class="card">
|
|
535
|
-
<p>Use a padded container after summary to avoid edge-to-edge content.</p>
|
|
536
|
-
</div>
|
|
537
|
-
</details>
|
|
538
|
-
```
|
|
539
|
-
|
|
540
|
-
### Empty State Pattern
|
|
541
|
-
|
|
542
|
-
- Use the `.empty-state` primitive for empty or onboarding states.
|
|
543
|
-
- Structure: heading + supporting text, an icon, then primary/secondary actions.
|
|
544
|
-
- Keep actions as buttons or links with PDS button classes, and include a meaningful icon when available.
|
|
545
|
-
|
|
546
|
-
```javascript
|
|
547
|
-
// Dialogs & Toasts: PDS API
|
|
548
|
-
const confirmed = await PDS.ask("Delete this item?", {
|
|
549
|
-
type: "confirm",
|
|
550
|
-
buttons: { ok: { name: "Delete", variant: "danger" } }
|
|
551
|
-
});
|
|
552
|
-
|
|
553
|
-
const result = await PDS.ask("Publish this change?", {
|
|
554
|
-
title: "Final approval",
|
|
555
|
-
buttons: {
|
|
556
|
-
ok: { name: "Publish", primary: true },
|
|
557
|
-
cancel: { name: "Cancel", cancel: true }
|
|
558
|
-
},
|
|
559
|
-
beforeClose: async ({ actionKind }) => {
|
|
560
|
-
if (actionKind !== "ok") return true;
|
|
561
|
-
const response = await fetch("/api/publish/can-close", { method: "POST" });
|
|
562
|
-
if (!response.ok) return { allow: false };
|
|
563
|
-
const payload = await response.json();
|
|
564
|
-
return { allow: payload?.ok === true };
|
|
565
|
-
}
|
|
566
|
-
});
|
|
567
|
-
|
|
568
|
-
await PDS.toast("Saved successfully!", { type: "success" });
|
|
569
|
-
|
|
570
|
-
// Theme management
|
|
571
|
-
PDS.theme = 'dark'; // 'light' | 'dark' | 'system'
|
|
572
|
-
|
|
573
|
-
// Query the design system via MCP tool: query_design_system
|
|
574
|
-
```
|
|
61
|
+
## Intent Scoping
|
|
575
62
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
## 📚 Additional Resources
|
|
63
|
+
Match implementation to the smallest relevant layer first:
|
|
579
64
|
|
|
580
|
-
**
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
- Check [custom-elements.json](https://github.com/Pure-Web-Foundation/pure-ds/blob/main/custom-elements.json) for component API details
|
|
65
|
+
1. **Layer 1**: CSS tokens + utility classes + primitive classes (`.card`, `.btn-*`, `.flex`, `.grid-*`)
|
|
66
|
+
2. **Layer 2**: `data-*` enhancements (`data-dropdown`, `data-toggle`, `data-required`)
|
|
67
|
+
3. **Layer 3**: Web Components — only when native HTML has no equivalent
|
|
584
68
|
|
|
585
|
-
|
|
586
|
-
- Use `PDS.toast()` method (see [src/js/common/toast.js](https://github.com/Pure-Web-Foundation/pure-ds/blob/main/src/js/common/toast.js) for implementation)
|
|
587
|
-
- Automatically ensures pds-toaster exists and is loaded before displaying
|
|
588
|
-
- See pds-toaster component API in [custom-elements.json](https://github.com/Pure-Web-Foundation/pure-ds/blob/main/custom-elements.json)
|
|
69
|
+
Do not inspect or modify `pds-form` unless the request explicitly involves that component.
|
|
589
70
|
|
|
590
71
|
---
|
|
591
72
|
|
|
592
|
-
##
|
|
73
|
+
## Critical Anti-Patterns
|
|
593
74
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
75
|
+
- ❌ `style="..."` → use `var(--token-name)` CSS custom properties
|
|
76
|
+
- ❌ Hardcoded colors / spacing → tokens: `--color-*`, `--spacing-*`, `--radius-*`
|
|
77
|
+
- ❌ `alert()` / `confirm()` / `prompt()` → `PDS.ask()` / `PDS.toast()`
|
|
78
|
+
- ❌ Manual dropdown / modal / tab → `<nav data-dropdown>`, `PDS.ask()`, `<pds-tabstrip>`
|
|
79
|
+
- ❌ Native `submit` event on pds-form → listen to `pw:submit`
|
|
80
|
+
- ❌ Accessing lazy component before definition → `await customElements.whenDefined('tag-name')`
|
|
81
|
+
- ❌ Missing `btn-working` class during async button operations
|
|
82
|
+
- ❌ `<div class="button">` or other non-semantic HTML → `<button class="btn-primary">`
|
|
83
|
+
- ❌ `ui:icon` on non-text-like inputs (date-range, textarea, select, omnibox)
|
|
84
|
+
- ❌ Importing localization helpers from `#pds/lit` → import from `#pds`
|
|
602
85
|
|
|
603
86
|
---
|
|
604
87
|
|
|
605
88
|
## Summary Checklist
|
|
606
89
|
|
|
607
|
-
Before generating code:
|
|
608
|
-
|
|
609
|
-
1. ✅ **
|
|
610
|
-
2. ✅ **No inline styles** —
|
|
611
|
-
3. ✅ **No
|
|
612
|
-
4. ✅ **
|
|
613
|
-
5. ✅ **
|
|
614
|
-
6. ✅ **
|
|
615
|
-
7. ✅ **
|
|
616
|
-
8. ✅ **
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
**For pds-form specifically:**
|
|
621
|
-
|
|
622
|
-
11. ✅ **Use `pw:submit` event** — NOT native `submit` event
|
|
623
|
-
12. ✅ **Add `btn-working` class** — For async submit operations, add during processing
|
|
624
|
-
13. ✅ **Use `examples` in JSON schema** — First example becomes placeholder
|
|
625
|
-
14. ✅ **Add smart icons** — Infer icons based on field names (email→envelope, phone→phone)
|
|
626
|
-
15. ✅ **Wrap in `form[data-required]`** — For asterisk enhancement on required fields
|
|
627
|
-
16. ✅ **Pad details content** — After `<summary>`, wrap content in a padded container (usually `.card`)
|
|
90
|
+
Before generating any code:
|
|
91
|
+
|
|
92
|
+
1. ✅ **Call MCP first** — `query_design_system`, `get_component_api`, `find_utility_class` as needed
|
|
93
|
+
2. ✅ **No inline styles** — CSS custom property tokens only
|
|
94
|
+
3. ✅ **No browser dialogs** — `PDS.ask()` and `PDS.toast()`
|
|
95
|
+
4. ✅ **Semantic HTML** — `<button>`, `<nav>`, `<article>`, `<label>`, `<details>`
|
|
96
|
+
5. ✅ **Enhancements via `data-*`** — not manual JavaScript
|
|
97
|
+
6. ✅ **Components as last resort** — prefer primitives and enhancements
|
|
98
|
+
7. ✅ **Await lazy-loaded components** — `await customElements.whenDefined()`
|
|
99
|
+
8. ✅ **Validate generated HTML** — `validate_pds_snippet`
|
|
100
|
+
|
|
101
|
+
> **For all topic-specific patterns** (pds-form, localization, DOM building, toasts, treeview, Lit import maps), call `query_design_system("your question")` — it returns authoritative guidance with live code examples straight from source.
|