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