@pure-ds/core 0.7.56 → 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.
Files changed (33) hide show
  1. package/.cursorrules +63 -589
  2. package/.github/copilot-instructions.md +63 -598
  3. package/custom-elements.json +110 -5
  4. package/dist/types/pds.d.ts +65 -0
  5. package/dist/types/src/js/common/common.d.ts +7 -0
  6. package/dist/types/src/js/common/common.d.ts.map +1 -1
  7. package/dist/types/src/js/pds-autocomplete.d.ts +74 -1
  8. package/dist/types/src/js/pds-autocomplete.d.ts.map +1 -1
  9. package/dist/types/src/js/pds-core/pds-start-helpers.d.ts.map +1 -1
  10. package/dist/types/src/js/pds-reactive.d.ts +101 -0
  11. package/dist/types/src/js/pds-reactive.d.ts.map +1 -0
  12. package/dist/types/src/js/pds.d.ts +4 -1
  13. package/dist/types/src/js/pds.d.ts.map +1 -1
  14. package/package.json +1 -2
  15. package/packages/pds-cli/lib/pds-mcp-core.js +436 -1
  16. package/public/assets/js/app.js +7 -6
  17. package/public/assets/js/pds-ask.js +4 -4
  18. package/public/assets/js/pds-autocomplete.js +7 -7
  19. package/public/assets/js/pds-manager.js +144 -143
  20. package/public/assets/js/pds.js +3 -2
  21. package/public/assets/pds/components/pds-calendar.js +103 -7
  22. package/public/assets/pds/components/pds-fab.js +2 -2
  23. package/public/assets/pds/core/pds-ask.js +4 -4
  24. package/public/assets/pds/core/pds-autocomplete.js +7 -7
  25. package/public/assets/pds/core/pds-manager.js +144 -143
  26. package/public/assets/pds/core.js +3 -2
  27. package/public/assets/pds/custom-elements.json +382 -28
  28. package/public/assets/pds/pds-css-complete.json +1 -1
  29. package/public/assets/pds/vscode-custom-data.json +29 -1
  30. package/src/js/common/common.js +74 -0
  31. package/src/js/pds-core/pds-start-helpers.js +17 -2
  32. package/src/js/pds.d.ts +65 -0
  33. package/src/js/pds.js +13 -0
package/.cursorrules CHANGED
@@ -1,627 +1,101 @@
1
- # PDS (Pure Design System) - AI Generation Instructions
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 we are in the pure-ds (@pure-ds/core origin) project itself, `/pds/` PATHS ARE READ-ONLY (PACKAGE-LIKE)**: Treat any file path containing `/pds/` as immutable runtime/package output (including `public/pds/**`, `public/assets/pds/**`, and `node_modules/@pure-ds/core/public/**`). Never patch these files directly. If behavior must change, edit source/config (`src/js/pds-core/**`, `pds.config.js`, component source), then rebuild.
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: in the pure-ds (@pure-ds/core origin) project itself**, pds-* web components ARE not compiled from source. The pds-* components in pds/components/ ARE their own source code!
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
- 1. **Standards-first**: Web Platform APIs only (no framework dependencies)
14
- 2. **Configuration-driven**: `pds.config.js` generates everything
15
- 3. **Progressive Enhancement**: Semantic HTML first, enhance where needed
16
- 4. **Components as Last Resort**: Web Components only when native HTML cannot achieve it
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
- **Layer 2Enhancements**: Behavior added to semantic HTML via selector-based upgrades (`data-dropdown`, `data-toggle`, etc.).
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
- ## 🔍 Single Sources of Truth (ALWAYS CONSULT THESE FIRST)
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
- ## 🎯 Intent Scoping (Avoid Wrong Surface Area)
26
+ > In consuming projects, prefix paths with `node_modules/@pure-ds/core/`.
82
27
 
83
- Always match the implementation target to the user request before touching code.
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
- - If the request is generic layout/styling (e.g., "grid", "mobile one column", spacing, alignment), solve it with primitives/utilities/config first (`.grid`, `.grid-cols-*`, responsive utilities, `pds-ontology.js`, `pds.config.js`).
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
- ## 📋 pds-form Best Practices
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
- // NEVER: Access lazy-loaded component APIs before they're defined
373
- const form = document.querySelector('pds-form');
374
- form.getFormData(); // May fail - component not loaded yet
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
- // NEVER: Use native 'submit' event with pds-form
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
- // NEVER: Forget btn-working class for async operations
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
- ## Quick Reference Patterns
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
- **For comprehensive pds-form documentation:**
581
- - Read [pds-form-docs.md](https://github.com/Pure-Web-Foundation/pure-ds/blob/main/pds-form-docs.md) for complete API reference
582
- - See [packages/pds-storybook/stories/components/PdsForm.stories.js](https://github.com/Pure-Web-Foundation/pure-ds/blob/main/packages/pds-storybook/stories/components/PdsForm.stories.js) for real examples
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
- **For toast notifications:**
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
- ## How to Look Things Up
73
+ ## Critical Anti-Patterns
593
74
 
594
- | Question | Action |
595
- |----------|--------|
596
- | "What CSS tokens exist?" | Read `pds.css-data.json` |
597
- | "What components are available?" | Read `custom-elements.json` |
598
- | "What utility classes exist?" | Read `pds-ontology.js``layoutPatterns`, `utilities` |
599
- | "What primitives exist?" | Read `pds-ontology.js` → `primitives` |
600
- | "How do I enhance HTML?" | Read `pds-enhancers.js` `defaultPDSEnhancerMetadata` `demoHtml` |
601
- | "How are tokens named?" | Read `pds-generator.js` or `pds.css-data.json` |
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-formlisten 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. ✅ **Consult SSoT files** — Don't guess class names or token names
610
- 2. ✅ **No inline styles** — Use CSS tokens via custom properties
611
- 3. ✅ **No hardcoded values** — Colors, spacing, radii all have tokens
612
- 4. ✅ **No alert/confirm/prompt** — Use `PDS.ask()` and `PDS.toast()`
613
- 5. ✅ **Use semantic HTML**`<button>`, `<nav>`, `<article>`, `<label>`, `<details>`
614
- 6. ✅ **Apply enhancements via data-* attributes** — See `pds-enhancers.js` `defaultPDSEnhancerMetadata`
615
- 7. ✅ **Components as last resort** — Only when native HTML can't achieve it
616
- 8. ✅ **Prefer primitives** — `.card`, `.badge`, `.callout` over custom components
617
- 9. ✅ **Wait for lazy components** — Use `await customElements.whenDefined()` before accessing APIs
618
- 10. **Include import map** When using `pds-form` or `pds-drawer`, ensure `#pds/lit` is mapped
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.