@pure-ds/storybook 0.4.16 → 0.4.19
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/.storybook/addons/html-preview/Panel.jsx +80 -29
- package/.storybook/addons/html-preview/preview.js +4 -5
- package/.storybook/manager.js +337 -49
- package/.storybook/preview-head.html +2 -2
- package/.storybook/preview.js +2 -2
- package/README.md +2 -2
- package/dist/pds-reference.json +1916 -267
- package/package.json +2 -2
- package/public/assets/css/app.css +2 -2
- package/public/assets/js/app.js +645 -10574
- package/public/assets/js/lit.js +3 -1048
- package/public/assets/js/pds.js +429 -7368
- package/public/assets/pds/components/pds-calendar.js +1 -1
- package/public/assets/pds/components/{pds-jsonform.js → pds-form.js} +536 -45
- package/public/assets/pds/custom-elements.json +271 -26
- package/public/assets/pds/pds-runtime-config.json +1 -1
- package/public/assets/pds/styles/pds-components.css +83 -221
- package/public/assets/pds/styles/pds-components.css.js +166 -442
- package/public/assets/pds/styles/pds-styles.css +240 -437
- package/public/assets/pds/styles/pds-styles.css.js +479 -881
- package/public/assets/pds/styles/pds-utilities.css +151 -214
- package/public/assets/pds/styles/pds-utilities.css.js +302 -428
- package/public/assets/pds/vscode-custom-data.json +63 -63
- package/scripts/build-pds-reference.mjs +112 -38
- package/scripts/generate-stories.js +2 -2
- package/src/js/common/ask.js +48 -21
- package/src/js/pds-configurator/pds-config-form.js +9 -9
- package/src/js/pds-configurator/pds-demo.js +2 -2
- package/src/js/pds-core/pds-config.js +14 -14
- package/src/js/pds-core/pds-generator.js +113 -50
- package/src/js/pds-core/pds-ontology.js +6 -6
- package/src/js/pds.d.ts +2 -2
- package/stories/GettingStarted.stories.js +3 -0
- package/stories/WhatIsPDS.stories.js +3 -0
- package/stories/components/PdsCalendar.stories.js +2 -2
- package/stories/components/PdsDrawer.stories.js +15 -15
- package/stories/components/PdsForm.stories.js +4356 -0
- package/stories/components/{PdsJsonformUiSchema.md → PdsFormUiSchema.md} +2 -2
- package/stories/components/PdsRichtext.stories.js +4 -17
- package/stories/components/PdsScrollrow.stories.js +224 -72
- package/stories/components/PdsSplitpanel.stories.js +63 -28
- package/stories/components/PdsTabstrip.stories.js +7 -7
- package/stories/enhancements/Accordion.stories.js +2 -2
- package/stories/enhancements/Dropdowns.stories.js +13 -10
- package/stories/enhancements/RangeSliders.stories.js +9 -9
- package/stories/enhancements/RequiredFields.stories.js +8 -8
- package/stories/enhancements/Toggles.stories.js +45 -36
- package/stories/enhancements/_enhancement-header.js +2 -2
- package/stories/foundations/Colors.stories.js +13 -13
- package/stories/foundations/HTMLDefaults.stories.js +4 -4
- package/stories/foundations/Icons.stories.js +123 -288
- package/stories/foundations/MeshGradients.stories.js +161 -250
- package/stories/foundations/SmartSurfaces.stories.js +147 -64
- package/stories/foundations/Spacing.stories.js +30 -30
- package/stories/foundations/Typography.stories.js +352 -723
- package/stories/foundations/ZIndex.stories.js +124 -141
- package/stories/layout/LayoutOverview.stories.js +345 -250
- package/stories/layout/LayoutSystem.stories.js +60 -76
- package/stories/patterns/InteractiveStates.stories.js +29 -29
- package/stories/patterns/Utilities.stories.js +17 -5
- package/stories/primitives/Alerts.stories.js +6 -6
- package/stories/primitives/Cards.stories.js +22 -11
- package/stories/primitives/{Forms.stories.js → FormElements.stories.js} +20 -11
- package/stories/primitives/HtmlFormElements.stories.js +128 -0
- package/stories/primitives/{FormGroups.stories.js → HtmlFormGroups.stories.js} +70 -21
- package/stories/primitives/Media.stories.js +23 -20
- package/stories/utilities/Backdrop.stories.js +68 -27
- package/stories/utils/PdsAsk.stories.js +15 -14
- package/public/assets/js/app.js.map +0 -7
- package/public/assets/js/lit.js.map +0 -7
- package/public/assets/js/pds.js.map +0 -7
- package/stories/components/PdsJsonform.stories.js +0 -1929
- /package/src/{pds-core → node-api}/pds-api.js +0 -0
package/.storybook/manager.js
CHANGED
|
@@ -25,6 +25,67 @@ let categoryIndex = new Map();
|
|
|
25
25
|
/** @type {Map<string, Set<string>>} Tag to items that have that tag */
|
|
26
26
|
let tagIndex = new Map();
|
|
27
27
|
|
|
28
|
+
/** @type {Set<string>} All searchable words from ontology (for prefix matching) */
|
|
29
|
+
let allWords = new Set();
|
|
30
|
+
|
|
31
|
+
/** @type {Map<string, string[]>} Story ID to its pds.tags (extracted from story parameters) */
|
|
32
|
+
let storyTagsIndex = new Map();
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Build story tags index from the storyIndex in pds-reference.json
|
|
36
|
+
* This is populated during loadOntology() from the pre-built reference data
|
|
37
|
+
*/
|
|
38
|
+
function buildStoryTagsIndex() {
|
|
39
|
+
if (!referenceData?.storyIndex) return;
|
|
40
|
+
|
|
41
|
+
let tagCount = 0;
|
|
42
|
+
|
|
43
|
+
// Helper to convert title to Storybook ID format
|
|
44
|
+
// "About PDS/What Is PDS" → "about-pds-what-is-pds"
|
|
45
|
+
const titleToId = (title) => {
|
|
46
|
+
return title
|
|
47
|
+
.toLowerCase()
|
|
48
|
+
.replace(/[^a-z0-9/\s-]/g, '')
|
|
49
|
+
.replace(/[\s/]+/g, '-')
|
|
50
|
+
.replace(/-+/g, '-')
|
|
51
|
+
.replace(/^-|-$/g, '');
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
Object.entries(referenceData.storyIndex).forEach(([slug, entry]) => {
|
|
55
|
+
if (!Array.isArray(entry.tags) || entry.tags.length === 0) return;
|
|
56
|
+
|
|
57
|
+
const normalizedTags = entry.tags.map(t => String(t).toLowerCase());
|
|
58
|
+
|
|
59
|
+
// Compute the Storybook component ID from the title
|
|
60
|
+
const componentId = entry.storyTitle ? titleToId(entry.storyTitle) : slug;
|
|
61
|
+
|
|
62
|
+
// Index by multiple possible ID formats
|
|
63
|
+
const idsToIndex = [
|
|
64
|
+
slug.toLowerCase(),
|
|
65
|
+
componentId,
|
|
66
|
+
// Also add story variant IDs if we have story names
|
|
67
|
+
...(entry.stories || []).map(s => s.id?.toLowerCase()).filter(Boolean)
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
idsToIndex.forEach(id => {
|
|
71
|
+
if (id) {
|
|
72
|
+
storyTagsIndex.set(id, normalizedTags);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Add tags to allWords for prefix matching
|
|
77
|
+
normalizedTags.forEach(tag => {
|
|
78
|
+
allWords.add(tag);
|
|
79
|
+
// Add individual words from multi-word tags
|
|
80
|
+
tag.split(/\s+/).forEach(word => {
|
|
81
|
+
if (word.length >= 2) allWords.add(word);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
tagCount += normalizedTags.length;
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
28
89
|
/**
|
|
29
90
|
* Load ontology data from pds-reference.json
|
|
30
91
|
* This file is generated by build-pds-reference.mjs from the SSoT (pds-ontology.js)
|
|
@@ -38,16 +99,11 @@ async function loadOntology() {
|
|
|
38
99
|
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
39
100
|
referenceData = await response.json();
|
|
40
101
|
buildIndices();
|
|
41
|
-
|
|
42
|
-
searchRelations: Object.keys(referenceData.ontologyData?.searchRelations || {}).length,
|
|
43
|
-
primitives: referenceData.ontologyData?.primitives?.length || 0,
|
|
44
|
-
components: referenceData.ontologyData?.components?.length || 0,
|
|
45
|
-
enhancements: referenceData.ontologyData?.enhancements?.length || 0
|
|
46
|
-
});
|
|
102
|
+
buildStoryTagsIndex();
|
|
47
103
|
return referenceData;
|
|
48
104
|
} catch (err) {
|
|
49
105
|
console.warn('PDS Ontology: Failed to load pds-reference.json', err);
|
|
50
|
-
referenceData = { components: {}, ontologyData: {}, enhancements: [], tokens: {} };
|
|
106
|
+
referenceData = { components: {}, ontologyData: {}, enhancements: [], tokens: {}, storyIndex: {} };
|
|
51
107
|
return referenceData;
|
|
52
108
|
}
|
|
53
109
|
}
|
|
@@ -202,13 +258,122 @@ function buildIndices() {
|
|
|
202
258
|
});
|
|
203
259
|
});
|
|
204
260
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
261
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
262
|
+
// 6. Build allWords set for prefix matching
|
|
263
|
+
// Collect ALL words from all indices for comprehensive prefix search
|
|
264
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
265
|
+
relationIndex.forEach((related, key) => {
|
|
266
|
+
allWords.add(key);
|
|
267
|
+
related.forEach(r => allWords.add(r));
|
|
268
|
+
});
|
|
269
|
+
categoryIndex.forEach((members, cat) => {
|
|
270
|
+
allWords.add(cat);
|
|
271
|
+
members.forEach(m => allWords.add(m));
|
|
272
|
+
});
|
|
273
|
+
tagIndex.forEach((items, tag) => {
|
|
274
|
+
allWords.add(tag);
|
|
275
|
+
items.forEach(i => allWords.add(i));
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
// Add words from components
|
|
279
|
+
Object.values(referenceData.components || {}).forEach(comp => {
|
|
280
|
+
if (comp.tag) allWords.add(comp.tag.toLowerCase());
|
|
281
|
+
if (comp.displayName) allWords.add(comp.displayName.toLowerCase());
|
|
282
|
+
(comp.pdsTags || comp.ontology?.tags || []).forEach(t => allWords.add(t.toLowerCase()));
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
// Add words from primitives
|
|
286
|
+
(od.primitives || []).forEach(p => {
|
|
287
|
+
if (p.id) allWords.add(p.id.toLowerCase());
|
|
288
|
+
if (p.name) allWords.add(p.name.toLowerCase());
|
|
289
|
+
(p.tags || []).forEach(t => allWords.add(t.toLowerCase()));
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// Add words from enhancements
|
|
293
|
+
(od.enhancements || []).forEach(e => {
|
|
294
|
+
if (e.id) allWords.add(e.id.toLowerCase());
|
|
295
|
+
if (e.name) allWords.add(e.name.toLowerCase());
|
|
296
|
+
if (e.selector) allWords.add(e.selector.replace(/[[\]]/g, '').toLowerCase());
|
|
297
|
+
(e.tags || []).forEach(t => allWords.add(t.toLowerCase()));
|
|
209
298
|
});
|
|
210
299
|
}
|
|
211
300
|
|
|
301
|
+
/**
|
|
302
|
+
* Normalize a word to its singular form (simple English rules)
|
|
303
|
+
* Also returns the plural form so both directions match
|
|
304
|
+
* @param {string} word - Word to normalize
|
|
305
|
+
* @returns {string[]} - Array of [singular, plural] forms
|
|
306
|
+
*/
|
|
307
|
+
function normalizePlural(word) {
|
|
308
|
+
const w = word.toLowerCase();
|
|
309
|
+
const forms = new Set([w]);
|
|
310
|
+
|
|
311
|
+
// Common irregular plurals
|
|
312
|
+
const irregulars = {
|
|
313
|
+
'children': 'child', 'child': 'children',
|
|
314
|
+
'people': 'person', 'person': 'people',
|
|
315
|
+
'men': 'man', 'man': 'men',
|
|
316
|
+
'women': 'woman', 'woman': 'women',
|
|
317
|
+
'mice': 'mouse', 'mouse': 'mice',
|
|
318
|
+
'feet': 'foot', 'foot': 'feet',
|
|
319
|
+
'teeth': 'tooth', 'tooth': 'teeth',
|
|
320
|
+
'geese': 'goose', 'goose': 'geese',
|
|
321
|
+
'indices': 'index', 'index': 'indices',
|
|
322
|
+
'matrices': 'matrix', 'matrix': 'matrices',
|
|
323
|
+
'vertices': 'vertex', 'vertex': 'vertices',
|
|
324
|
+
'data': 'datum', 'datum': 'data',
|
|
325
|
+
'media': 'medium', 'medium': 'media'
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
if (irregulars[w]) {
|
|
329
|
+
forms.add(irregulars[w]);
|
|
330
|
+
return [...forms];
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// -ies → -y (e.g., utilities → utility)
|
|
334
|
+
if (w.endsWith('ies')) {
|
|
335
|
+
forms.add(w.slice(0, -3) + 'y');
|
|
336
|
+
}
|
|
337
|
+
// -y → -ies (e.g., utility → utilities)
|
|
338
|
+
if (w.endsWith('y') && !['ay', 'ey', 'oy', 'uy'].some(v => w.endsWith(v))) {
|
|
339
|
+
forms.add(w.slice(0, -1) + 'ies');
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// -es → base (e.g., boxes → box, classes → class)
|
|
343
|
+
if (w.endsWith('ses') || w.endsWith('xes') || w.endsWith('zes') ||
|
|
344
|
+
w.endsWith('ches') || w.endsWith('shes')) {
|
|
345
|
+
forms.add(w.slice(0, -2));
|
|
346
|
+
}
|
|
347
|
+
// Add -es for words ending in s, x, z, ch, sh
|
|
348
|
+
if (w.endsWith('s') || w.endsWith('x') || w.endsWith('z') ||
|
|
349
|
+
w.endsWith('ch') || w.endsWith('sh')) {
|
|
350
|
+
forms.add(w + 'es');
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// -ves → -f/-fe (e.g., leaves → leaf)
|
|
354
|
+
if (w.endsWith('ves')) {
|
|
355
|
+
forms.add(w.slice(0, -3) + 'f');
|
|
356
|
+
forms.add(w.slice(0, -3) + 'fe');
|
|
357
|
+
}
|
|
358
|
+
// -f/-fe → -ves
|
|
359
|
+
if (w.endsWith('f')) {
|
|
360
|
+
forms.add(w.slice(0, -1) + 'ves');
|
|
361
|
+
}
|
|
362
|
+
if (w.endsWith('fe')) {
|
|
363
|
+
forms.add(w.slice(0, -2) + 'ves');
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Simple -s rule (most common)
|
|
367
|
+
if (w.endsWith('s') && w.length > 2 && !w.endsWith('ss')) {
|
|
368
|
+
forms.add(w.slice(0, -1)); // Remove trailing s
|
|
369
|
+
}
|
|
370
|
+
if (!w.endsWith('s')) {
|
|
371
|
+
forms.add(w + 's'); // Add trailing s
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
return [...forms];
|
|
375
|
+
}
|
|
376
|
+
|
|
212
377
|
/**
|
|
213
378
|
* Expand a search query using ontology indices
|
|
214
379
|
* @param {string} query - User's search term
|
|
@@ -220,31 +385,69 @@ function expandQuery(query) {
|
|
|
220
385
|
|
|
221
386
|
const terms = new Set([q]);
|
|
222
387
|
|
|
223
|
-
//
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
}
|
|
388
|
+
// Add singular/plural forms of the query
|
|
389
|
+
const queryVariants = normalizePlural(q);
|
|
390
|
+
queryVariants.forEach(form => terms.add(form));
|
|
227
391
|
|
|
228
|
-
//
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
392
|
+
// Helper: check index with all variants of a term
|
|
393
|
+
const checkIndexWithVariants = (index, variants, addRelated = true) => {
|
|
394
|
+
variants.forEach(variant => {
|
|
395
|
+
if (index.has(variant)) {
|
|
396
|
+
terms.add(variant);
|
|
397
|
+
if (addRelated) {
|
|
398
|
+
index.get(variant).forEach(t => {
|
|
399
|
+
terms.add(t);
|
|
400
|
+
// Also add plural/singular of related terms
|
|
401
|
+
normalizePlural(t).forEach(form => terms.add(form));
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
};
|
|
232
407
|
|
|
233
|
-
//
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
408
|
+
// 1. Check searchRelations with all variants (primary SSoT for relationships)
|
|
409
|
+
checkIndexWithVariants(relationIndex, queryVariants);
|
|
410
|
+
|
|
411
|
+
// 2. Check categories with all variants
|
|
412
|
+
checkIndexWithVariants(categoryIndex, queryVariants);
|
|
413
|
+
|
|
414
|
+
// 3. Check tags with all variants
|
|
415
|
+
checkIndexWithVariants(tagIndex, queryVariants);
|
|
237
416
|
|
|
238
|
-
// 4. Partial matches
|
|
239
|
-
//
|
|
417
|
+
// 4. Partial/prefix matches for queries 3+ chars
|
|
418
|
+
// Find any indexed term that STARTS WITH the query (e.g., "notif" → "notification")
|
|
240
419
|
if (q.length >= 3) {
|
|
420
|
+
// Check relation keys for prefix matches
|
|
241
421
|
relationIndex.forEach((related, key) => {
|
|
242
|
-
|
|
243
|
-
const isPrefix = key.startsWith(q) || q.startsWith(key);
|
|
244
|
-
const isSuffix = key.endsWith(q) || q.endsWith(key);
|
|
245
|
-
if (isPrefix || isSuffix) {
|
|
422
|
+
if (key.startsWith(q)) {
|
|
246
423
|
terms.add(key);
|
|
247
|
-
//
|
|
424
|
+
// Also add plural/singular variants of matched key
|
|
425
|
+
normalizePlural(key).forEach(form => terms.add(form));
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
// Check category keys for prefix matches
|
|
430
|
+
categoryIndex.forEach((members, cat) => {
|
|
431
|
+
if (cat.startsWith(q)) {
|
|
432
|
+
terms.add(cat);
|
|
433
|
+
normalizePlural(cat).forEach(form => terms.add(form));
|
|
434
|
+
}
|
|
435
|
+
// Also check category members for prefix matches
|
|
436
|
+
members.forEach(member => {
|
|
437
|
+
if (member.startsWith(q)) {
|
|
438
|
+
terms.add(member);
|
|
439
|
+
normalizePlural(member).forEach(form => terms.add(form));
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
// Check tag keys for prefix matches
|
|
445
|
+
tagIndex.forEach((items, tag) => {
|
|
446
|
+
if (tag.startsWith(q)) {
|
|
447
|
+
terms.add(tag);
|
|
448
|
+
normalizePlural(tag).forEach(form => terms.add(form));
|
|
449
|
+
// Also add the items that have this tag
|
|
450
|
+
items.forEach(item => terms.add(item));
|
|
248
451
|
}
|
|
249
452
|
});
|
|
250
453
|
}
|
|
@@ -257,27 +460,65 @@ function expandQuery(query) {
|
|
|
257
460
|
const name = comp.displayName?.toLowerCase();
|
|
258
461
|
const tagWithoutPrefix = tag?.replace('pds-', '');
|
|
259
462
|
|
|
260
|
-
// Match if query equals or closely matches the component
|
|
261
|
-
|
|
262
|
-
|
|
463
|
+
// Match if query equals, is prefix of, or closely matches the component
|
|
464
|
+
const matchesComponent =
|
|
465
|
+
tag === q || name === q || tagWithoutPrefix === q ||
|
|
466
|
+
tag?.startsWith(q) || name?.startsWith(q) || tagWithoutPrefix?.startsWith(q) ||
|
|
467
|
+
tag?.includes(q) || name?.includes(q);
|
|
468
|
+
|
|
469
|
+
if (matchesComponent) {
|
|
263
470
|
terms.add(tag);
|
|
264
471
|
terms.add(tagWithoutPrefix);
|
|
265
472
|
terms.add(name);
|
|
266
|
-
// Don't add pdsTags - they're too generic and cause over-matching
|
|
267
473
|
}
|
|
268
474
|
});
|
|
269
475
|
}
|
|
270
476
|
|
|
271
|
-
// 6. Enhancement selectors
|
|
477
|
+
// 6. Enhancement selectors - also check prefix matches
|
|
272
478
|
(referenceData?.enhancements || []).forEach(e => {
|
|
273
479
|
const sel = e.selector?.toLowerCase();
|
|
274
480
|
const id = e.id?.toLowerCase();
|
|
275
|
-
|
|
481
|
+
const name = e.name?.toLowerCase();
|
|
482
|
+
if (sel?.startsWith(q) || sel?.includes(q) ||
|
|
483
|
+
id?.startsWith(q) || id?.includes(q) ||
|
|
484
|
+
name?.startsWith(q) || name?.includes(q)) {
|
|
276
485
|
terms.add(sel);
|
|
277
486
|
terms.add(id);
|
|
487
|
+
terms.add(name);
|
|
278
488
|
}
|
|
279
489
|
});
|
|
280
490
|
|
|
491
|
+
// 7. Primitives - check for prefix matches in IDs and tags
|
|
492
|
+
(referenceData?.ontologyData?.primitives || []).forEach(p => {
|
|
493
|
+
const id = p.id?.toLowerCase();
|
|
494
|
+
const pTags = p.tags || [];
|
|
495
|
+
|
|
496
|
+
if (id?.startsWith(q) || id?.includes(q)) {
|
|
497
|
+
terms.add(id);
|
|
498
|
+
normalizePlural(id).forEach(form => terms.add(form));
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
pTags.forEach(t => {
|
|
502
|
+
const tLower = t.toLowerCase();
|
|
503
|
+
if (tLower.startsWith(q) || tLower.includes(q)) {
|
|
504
|
+
terms.add(tLower);
|
|
505
|
+
normalizePlural(tLower).forEach(form => terms.add(form));
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
// 8. Global prefix matching against ALL indexed words
|
|
511
|
+
// This catches anything we might have missed above
|
|
512
|
+
if (q.length >= 3) {
|
|
513
|
+
allWords.forEach(word => {
|
|
514
|
+
if (word.startsWith(q) || word.includes(q)) {
|
|
515
|
+
terms.add(word);
|
|
516
|
+
// Also add plural/singular variants
|
|
517
|
+
normalizePlural(word).forEach(form => terms.add(form));
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
|
|
281
522
|
return Array.from(terms).filter(Boolean);
|
|
282
523
|
}
|
|
283
524
|
|
|
@@ -291,15 +532,70 @@ function matchesOntology(item, expandedTerms) {
|
|
|
291
532
|
if (!expandedTerms.length) return true;
|
|
292
533
|
|
|
293
534
|
// Build searchable text from item properties
|
|
294
|
-
const
|
|
535
|
+
const searchableParts = [
|
|
295
536
|
item.name,
|
|
296
537
|
item.title,
|
|
297
538
|
item.id,
|
|
298
539
|
item.importPath
|
|
299
|
-
]
|
|
540
|
+
];
|
|
541
|
+
|
|
542
|
+
// Include pre-indexed pds.tags for this story (from storyTagsIndex)
|
|
543
|
+
const storyId = item.id?.toLowerCase();
|
|
544
|
+
let foundTags = false;
|
|
545
|
+
|
|
546
|
+
if (storyId) {
|
|
547
|
+
// Try exact match
|
|
548
|
+
if (storyTagsIndex.has(storyId)) {
|
|
549
|
+
searchableParts.push(...storyTagsIndex.get(storyId));
|
|
550
|
+
foundTags = true;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// Try parent ID (for story variants like "about-pds-what-is-pds--whatispds")
|
|
554
|
+
const parentId = storyId.replace(/--[^-]+$/, '');
|
|
555
|
+
if (parentId !== storyId && storyTagsIndex.has(parentId)) {
|
|
556
|
+
searchableParts.push(...storyTagsIndex.get(parentId));
|
|
557
|
+
foundTags = true;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// Try partial match - check if any indexed ID is contained in this story ID
|
|
561
|
+
if (!foundTags) {
|
|
562
|
+
for (const [indexedId, tags] of storyTagsIndex.entries()) {
|
|
563
|
+
if (storyId.includes(indexedId) || indexedId.includes(storyId)) {
|
|
564
|
+
searchableParts.push(...tags);
|
|
565
|
+
foundTags = true;
|
|
566
|
+
break; // Found a match, no need to continue
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
const searchableText = searchableParts.filter(Boolean).join(' ').toLowerCase();
|
|
573
|
+
|
|
574
|
+
// Split searchable text into words for prefix matching
|
|
575
|
+
// Include both space-separated and path-separated words (for IDs like "components-pds-icon")
|
|
576
|
+
const searchableWords = searchableText.split(/[\s\-_/]+/).filter(w => w.length > 0);
|
|
300
577
|
|
|
301
578
|
// Match if ANY expanded term is found in the searchable text
|
|
302
|
-
|
|
579
|
+
// Also check plural/singular variants of each term
|
|
580
|
+
return expandedTerms.some(term => {
|
|
581
|
+
// Direct substring match
|
|
582
|
+
if (searchableText.includes(term)) return true;
|
|
583
|
+
|
|
584
|
+
// Check plural/singular variants
|
|
585
|
+
const variants = normalizePlural(term);
|
|
586
|
+
if (variants.some(variant => searchableText.includes(variant))) return true;
|
|
587
|
+
|
|
588
|
+
// Prefix matching for terms 3+ chars (e.g., "notif" matches "notification")
|
|
589
|
+
if (term.length >= 3) {
|
|
590
|
+
if (searchableWords.some(word => word.startsWith(term))) return true;
|
|
591
|
+
// Also check variants as prefixes
|
|
592
|
+
if (variants.some(variant =>
|
|
593
|
+
variant.length >= 3 && searchableWords.some(word => word.startsWith(variant))
|
|
594
|
+
)) return true;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
return false;
|
|
598
|
+
});
|
|
303
599
|
}
|
|
304
600
|
|
|
305
601
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -457,9 +753,6 @@ addons.register(ADDON_ID, (api) => {
|
|
|
457
753
|
if (searchField.dataset.pdsHooked) return;
|
|
458
754
|
searchField.dataset.pdsHooked = 'true';
|
|
459
755
|
|
|
460
|
-
console.log('%c🎨 PDS Ontology Search Active', 'color: #029cfd; font-weight: bold; font-size: 14px');
|
|
461
|
-
console.log('%cSearch expands via ontology relations. Try: "text", "form", "modal"', 'color: #999');
|
|
462
|
-
|
|
463
756
|
let debounceTimer;
|
|
464
757
|
searchField.addEventListener('input', (e) => {
|
|
465
758
|
clearTimeout(debounceTimer);
|
|
@@ -524,7 +817,7 @@ addons.register(ADDON_ID, (api) => {
|
|
|
524
817
|
});
|
|
525
818
|
mutationObserver.observe(document.body, { childList: true, subtree: true });
|
|
526
819
|
|
|
527
|
-
//
|
|
820
|
+
// Public API for programmatic search
|
|
528
821
|
window.pdsOntology = {
|
|
529
822
|
search: (query) => {
|
|
530
823
|
const field = document.getElementById('storybook-explorer-searchfield');
|
|
@@ -542,12 +835,7 @@ addons.register(ADDON_ID, (api) => {
|
|
|
542
835
|
field.dispatchEvent(new Event('input', { bubbles: true }));
|
|
543
836
|
}
|
|
544
837
|
applyFilter('');
|
|
545
|
-
}
|
|
546
|
-
data: () => referenceData,
|
|
547
|
-
relations: () => Object.fromEntries([...relationIndex].map(([k, v]) => [k, [...v]])),
|
|
548
|
-
categories: () => Object.fromEntries([...categoryIndex].map(([k, v]) => [k, [...v]])),
|
|
549
|
-
tags: () => Object.fromEntries([...tagIndex].map(([k, v]) => [k, [...v]])),
|
|
550
|
-
currentQuery: () => currentQuery
|
|
838
|
+
}
|
|
551
839
|
};
|
|
552
840
|
|
|
553
841
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
<!-- PDS runs in LIVE mode - styles are generated dynamically by Generator.applyStyles() -->
|
|
1
|
+
<!-- PDS runs in LIVE mode - styles are generated dynamically by Generator.applyStyles() -->
|
|
2
2
|
|
|
3
3
|
<!-- Source Code Pro font for code readability (like React.dev) -->
|
|
4
4
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
5
5
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
6
6
|
<link href="https://fonts.googleapis.com/css2?family=Source+Code+Pro:wght@400;500;600&display=swap" rel="stylesheet">
|
|
7
7
|
|
|
8
|
-
<!-- Import map for pds-
|
|
8
|
+
<!-- Import map for pds-form and other components that use #pds/lit -->
|
|
9
9
|
<script type="importmap">
|
|
10
10
|
{
|
|
11
11
|
"imports": {
|
package/.storybook/preview.js
CHANGED
|
@@ -1328,7 +1328,7 @@ const preview = {
|
|
|
1328
1328
|
'Enhancements',
|
|
1329
1329
|
['Mesh Gradients', 'Interactive States', 'Toggles', 'Dropdowns', 'Range Sliders', 'Required Fields'],
|
|
1330
1330
|
'Components',
|
|
1331
|
-
['
|
|
1331
|
+
['pds-form', 'Pds Icon', 'Pds Drawer', 'Pds Toaster', 'Pds Tabstrip', 'Pds Splitpanel', 'Pds Scrollrow', 'Pds Richtext', 'Pds Upload'],
|
|
1332
1332
|
'Reference'
|
|
1333
1333
|
],
|
|
1334
1334
|
'About PDS',
|
|
@@ -1346,7 +1346,7 @@ const preview = {
|
|
|
1346
1346
|
'Enhancements',
|
|
1347
1347
|
['Mesh Gradients', 'Interactive States', 'Toggles', 'Dropdowns', 'Range Sliders', 'Required Fields'],
|
|
1348
1348
|
'Components',
|
|
1349
|
-
['
|
|
1349
|
+
['pds-form', 'Pds Icon', 'Pds Drawer', 'Pds Toaster', 'Pds Tabstrip', 'Pds Splitpanel', 'Pds Scrollrow', 'Pds Richtext', 'Pds Upload'],
|
|
1350
1350
|
'Reference',
|
|
1351
1351
|
'*'
|
|
1352
1352
|
]
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# PDS Storybook
|
|
1
|
+
# PDS Storybook
|
|
2
2
|
|
|
3
3
|
**Pure Design System** Storybook showcase with live configuration capabilities.
|
|
4
4
|
|
|
@@ -58,7 +58,7 @@ Web Components (`<pds-*>`):
|
|
|
58
58
|
- `pds-upload` - File upload with preview
|
|
59
59
|
- `pds-toaster` - Toast notifications
|
|
60
60
|
- `pds-richtext` - Rich text editor (prefers `#showdown` import map; set `format="markdown"` to submit Markdown)
|
|
61
|
-
- `pds-
|
|
61
|
+
- `pds-form` - JSON Schema forms
|
|
62
62
|
- `pds-splitpanel` - Resizable panes
|
|
63
63
|
- `pds-scrollrow` - Horizontal scroll
|
|
64
64
|
|