@pure-ds/core 0.3.19 → 0.4.0
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/custom-elements.json +6 -6
- package/dist/types/pds.config.d.ts +4 -8
- package/dist/types/pds.config.d.ts.map +1 -1
- package/dist/types/pds.d.ts +408 -109
- package/dist/types/public/assets/js/pds.d.ts +3 -3
- package/dist/types/public/assets/js/pds.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-jsonform.d.ts +1 -0
- package/dist/types/public/assets/pds/components/pds-jsonform.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-tabstrip.d.ts +36 -5
- package/dist/types/public/assets/pds/components/pds-tabstrip.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-generator.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-ontology.d.ts +186 -12
- package/dist/types/src/js/pds-core/pds-ontology.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-query.d.ts.map +1 -1
- package/package.json +1 -1
- package/public/assets/js/app.js +304 -213
- package/public/assets/js/pds.js +172 -81
- package/public/assets/pds/components/pds-tabstrip.js +36 -5
- package/public/assets/pds/custom-elements.json +6 -6
- package/public/assets/pds/pds-css-complete.json +1 -1
- package/public/assets/pds/vscode-custom-data.json +4 -4
- package/src/js/pds-core/pds-generator.js +148 -57
- package/src/js/pds-core/pds-ontology.js +803 -256
- package/src/js/pds-core/pds-query.js +582 -571
|
@@ -1,256 +1,803 @@
|
|
|
1
|
-
// Pure Design System Ontology (PDS)
|
|
2
|
-
// This file is the single source-of-truth metadata for primitives, components, tokens, themes and enhancements.
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
1
|
+
// Pure Design System Ontology (PDS)
|
|
2
|
+
// This file is the single source-of-truth metadata for primitives, components, tokens, themes and enhancements.
|
|
3
|
+
// Used by PDS.query() for searching and correlating concepts.
|
|
4
|
+
|
|
5
|
+
export const ontology = {
|
|
6
|
+
meta: {
|
|
7
|
+
name: "Pure Design System Ontology",
|
|
8
|
+
version: "1.0.0",
|
|
9
|
+
description: "Complete metadata registry for PDS primitives, components, utilities, and tokens"
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
13
|
+
// DESIGN TOKENS
|
|
14
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
15
|
+
tokens: {
|
|
16
|
+
colors: {
|
|
17
|
+
semantic: ["primary", "secondary", "accent", "success", "warning", "danger", "info"],
|
|
18
|
+
neutral: ["gray"],
|
|
19
|
+
shades: [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950],
|
|
20
|
+
surface: ["base", "subtle", "elevated", "sunken", "overlay", "inverse", "translucent"],
|
|
21
|
+
text: ["default", "muted", "subtle", "inverse", "primary", "success", "warning", "danger", "info"]
|
|
22
|
+
},
|
|
23
|
+
spacing: {
|
|
24
|
+
scale: ["1", "2", "3", "4", "5", "6", "8", "10", "12", "16", "20", "24"],
|
|
25
|
+
semantic: ["xs", "sm", "md", "lg", "xl"]
|
|
26
|
+
},
|
|
27
|
+
typography: {
|
|
28
|
+
families: ["heading", "body", "mono"],
|
|
29
|
+
sizes: ["xs", "sm", "base", "lg", "xl", "2xl", "3xl", "4xl", "5xl"],
|
|
30
|
+
weights: ["light", "normal", "medium", "semibold", "bold"]
|
|
31
|
+
},
|
|
32
|
+
radius: {
|
|
33
|
+
scale: ["none", "sm", "base", "md", "lg", "xl", "2xl", "full"]
|
|
34
|
+
},
|
|
35
|
+
shadows: {
|
|
36
|
+
scale: ["none", "sm", "base", "md", "lg", "xl", "inner"]
|
|
37
|
+
},
|
|
38
|
+
themes: ["light", "dark"],
|
|
39
|
+
breakpoints: {
|
|
40
|
+
sm: 640,
|
|
41
|
+
md: 768,
|
|
42
|
+
lg: 1024,
|
|
43
|
+
xl: 1280
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
48
|
+
// PRIMITIVES (Single-class styled components)
|
|
49
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
50
|
+
primitives: [
|
|
51
|
+
{
|
|
52
|
+
id: "badge",
|
|
53
|
+
name: "Badge / Pill",
|
|
54
|
+
description: "Inline status indicators and labels",
|
|
55
|
+
selectors: [".badge", ".badge-primary", ".badge-secondary", ".badge-success", ".badge-info", ".badge-warning", ".badge-danger", ".badge-outline", ".badge-sm", ".badge-lg", ".pill", ".tag", ".chip"],
|
|
56
|
+
tags: ["status", "label", "indicator", "inline"],
|
|
57
|
+
category: "feedback"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: "card",
|
|
61
|
+
name: "Card",
|
|
62
|
+
description: "Content container with padding, border-radius, and optional shadow",
|
|
63
|
+
selectors: [".card", ".card-basic", ".card-elevated", ".card-outlined", ".card-interactive"],
|
|
64
|
+
tags: ["container", "content", "grouping"],
|
|
65
|
+
category: "container"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: "surface",
|
|
69
|
+
name: "Surface",
|
|
70
|
+
description: "Smart surface classes with automatic text/background color handling",
|
|
71
|
+
selectors: [".surface-base", ".surface-subtle", ".surface-elevated", ".surface-sunken", ".surface-overlay", ".surface-inverse", ".surface-translucent", ".surface-translucent-25", ".surface-translucent-50", ".surface-translucent-75", ".surface-primary", ".surface-secondary", ".surface-success", ".surface-warning", ".surface-danger", ".surface-info"],
|
|
72
|
+
tags: ["background", "theming", "color", "container"],
|
|
73
|
+
category: "theming"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
id: "alert",
|
|
77
|
+
name: "Alert",
|
|
78
|
+
description: "Contextual feedback messages",
|
|
79
|
+
selectors: [".alert", ".alert-info", ".alert-success", ".alert-warning", ".alert-danger", ".alert-error", ".alert-dismissible", ".semantic-message"],
|
|
80
|
+
tags: ["feedback", "message", "notification", "status"],
|
|
81
|
+
category: "feedback"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: "dialog",
|
|
85
|
+
name: "Dialog",
|
|
86
|
+
description: "Modal dialog element",
|
|
87
|
+
selectors: ["dialog", ".dialog"],
|
|
88
|
+
tags: ["modal", "overlay", "popup"],
|
|
89
|
+
category: "overlay"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
id: "divider",
|
|
93
|
+
name: "Divider",
|
|
94
|
+
description: "Horizontal rule with optional label",
|
|
95
|
+
selectors: ["hr", "hr[data-content]"],
|
|
96
|
+
tags: ["separator", "line", "content-divider"],
|
|
97
|
+
category: "layout"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
id: "table",
|
|
101
|
+
name: "Table",
|
|
102
|
+
description: "Data tables with responsive and styling variants",
|
|
103
|
+
selectors: ["table", ".table-responsive", ".table-striped", ".table-bordered", ".table-compact", ".data-table"],
|
|
104
|
+
tags: ["data", "grid", "tabular", "responsive"],
|
|
105
|
+
category: "data"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
id: "button",
|
|
109
|
+
name: "Button",
|
|
110
|
+
description: "Interactive button element with variants",
|
|
111
|
+
selectors: ["button", ".btn-primary", ".btn-secondary", ".btn-outline", ".btn-sm", ".btn-xs", ".btn-lg", ".btn-working", ".icon-only"],
|
|
112
|
+
tags: ["interactive", "action", "cta", "form"],
|
|
113
|
+
category: "action"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
id: "fieldset",
|
|
117
|
+
name: "Fieldset Group",
|
|
118
|
+
description: "Form field grouping for radio/checkbox groups",
|
|
119
|
+
selectors: ["fieldset[role='group']", "fieldset[role='radiogroup']", "fieldset.buttons"],
|
|
120
|
+
tags: ["form", "grouping", "radio", "checkbox"],
|
|
121
|
+
category: "form"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
id: "label-field",
|
|
125
|
+
name: "Label+Input",
|
|
126
|
+
description: "Semantic label wrapping form input",
|
|
127
|
+
selectors: ["label", "label:has(input)", "label:has(select)", "label:has(textarea)"],
|
|
128
|
+
tags: ["form", "input", "accessibility"],
|
|
129
|
+
category: "form"
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
id: "accordion",
|
|
133
|
+
name: "Accordion",
|
|
134
|
+
description: "Collapsible content sections",
|
|
135
|
+
selectors: [".accordion", ".accordion-item", "details", "details > summary"],
|
|
136
|
+
tags: ["expandable", "collapsible", "disclosure"],
|
|
137
|
+
category: "disclosure"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
id: "icon",
|
|
141
|
+
name: "Icon",
|
|
142
|
+
description: "SVG icon element with size and color variants",
|
|
143
|
+
selectors: ["pds-icon", ".icon-xs", ".icon-sm", ".icon-md", ".icon-lg", ".icon-xl", ".icon-primary", ".icon-secondary", ".icon-accent", ".icon-success", ".icon-warning", ".icon-danger", ".icon-info", ".icon-muted", ".icon-subtle", ".icon-text", ".icon-text-start", ".icon-text-end"],
|
|
144
|
+
tags: ["graphic", "symbol", "visual"],
|
|
145
|
+
category: "media"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
id: "figure",
|
|
149
|
+
name: "Figure/Media",
|
|
150
|
+
description: "Figure element for images with captions",
|
|
151
|
+
selectors: ["figure", "figure.media", "figcaption"],
|
|
152
|
+
tags: ["image", "media", "caption"],
|
|
153
|
+
category: "media"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
id: "gallery",
|
|
157
|
+
name: "Gallery",
|
|
158
|
+
description: "Image gallery grid",
|
|
159
|
+
selectors: [".gallery", ".gallery-grid", ".img-gallery"],
|
|
160
|
+
tags: ["images", "grid", "collection"],
|
|
161
|
+
category: "media"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
id: "form",
|
|
165
|
+
name: "Form Container",
|
|
166
|
+
description: "Form styling and layout",
|
|
167
|
+
selectors: ["form", ".form-container", ".form-actions", ".field-description"],
|
|
168
|
+
tags: ["form", "input", "submission"],
|
|
169
|
+
category: "form"
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
id: "navigation",
|
|
173
|
+
name: "Navigation",
|
|
174
|
+
description: "Navigation elements and menus",
|
|
175
|
+
selectors: ["nav", "nav[data-dropdown]", "menu", "nav menu li"],
|
|
176
|
+
tags: ["menu", "links", "routing"],
|
|
177
|
+
category: "navigation"
|
|
178
|
+
}
|
|
179
|
+
],
|
|
180
|
+
|
|
181
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
182
|
+
// WEB COMPONENTS
|
|
183
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
184
|
+
components: [
|
|
185
|
+
{
|
|
186
|
+
id: "pds-tabstrip",
|
|
187
|
+
name: "Tab Strip",
|
|
188
|
+
description: "Tabbed interface component",
|
|
189
|
+
selectors: ["pds-tabstrip"],
|
|
190
|
+
tags: ["tabs", "navigation", "panels"],
|
|
191
|
+
category: "navigation"
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
id: "pds-drawer",
|
|
195
|
+
name: "Drawer",
|
|
196
|
+
description: "Slide-out panel overlay",
|
|
197
|
+
selectors: ["pds-drawer"],
|
|
198
|
+
tags: ["panel", "overlay", "sidebar"],
|
|
199
|
+
category: "overlay"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
id: "pds-upload",
|
|
203
|
+
name: "Upload",
|
|
204
|
+
description: "File upload component with drag-and-drop",
|
|
205
|
+
selectors: ["pds-upload"],
|
|
206
|
+
tags: ["file", "upload", "drag-drop", "form"],
|
|
207
|
+
category: "form"
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
id: "pds-icon",
|
|
211
|
+
name: "Icon",
|
|
212
|
+
description: "SVG icon web component",
|
|
213
|
+
selectors: ["pds-icon"],
|
|
214
|
+
tags: ["icon", "graphic", "svg"],
|
|
215
|
+
category: "media"
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
id: "pds-toaster",
|
|
219
|
+
name: "Toaster",
|
|
220
|
+
description: "Toast notification container",
|
|
221
|
+
selectors: ["pds-toaster"],
|
|
222
|
+
tags: ["notification", "toast", "feedback"],
|
|
223
|
+
category: "feedback"
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
id: "pds-jsonform",
|
|
227
|
+
name: "JSON Form",
|
|
228
|
+
description: "Auto-generated form from JSON Schema",
|
|
229
|
+
selectors: ["pds-jsonform"],
|
|
230
|
+
tags: ["form", "schema", "auto-generate"],
|
|
231
|
+
category: "form"
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
id: "pds-splitpanel",
|
|
235
|
+
name: "Split Panel",
|
|
236
|
+
description: "Resizable split pane layout",
|
|
237
|
+
selectors: ["pds-splitpanel"],
|
|
238
|
+
tags: ["layout", "resize", "panels"],
|
|
239
|
+
category: "layout"
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
id: "pds-scrollrow",
|
|
243
|
+
name: "Scroll Row",
|
|
244
|
+
description: "Horizontal scrolling row with snap points",
|
|
245
|
+
selectors: ["pds-scrollrow"],
|
|
246
|
+
tags: ["scroll", "horizontal", "carousel"],
|
|
247
|
+
category: "layout"
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
id: "pds-richtext",
|
|
251
|
+
name: "Rich Text",
|
|
252
|
+
description: "Rich text editor component",
|
|
253
|
+
selectors: ["pds-richtext"],
|
|
254
|
+
tags: ["editor", "wysiwyg", "text"],
|
|
255
|
+
category: "form"
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
id: "pds-calendar",
|
|
259
|
+
name: "Calendar",
|
|
260
|
+
description: "Date picker calendar component",
|
|
261
|
+
selectors: ["pds-calendar"],
|
|
262
|
+
tags: ["date", "picker", "calendar"],
|
|
263
|
+
category: "form"
|
|
264
|
+
}
|
|
265
|
+
],
|
|
266
|
+
|
|
267
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
268
|
+
// LAYOUT PATTERNS
|
|
269
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
270
|
+
layoutPatterns: [
|
|
271
|
+
{
|
|
272
|
+
id: "container",
|
|
273
|
+
name: "Container",
|
|
274
|
+
description: "Centered max-width wrapper with padding",
|
|
275
|
+
selectors: [".container"],
|
|
276
|
+
tags: ["wrapper", "centered", "max-width", "page"],
|
|
277
|
+
category: "structure"
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
id: "grid",
|
|
281
|
+
name: "Grid",
|
|
282
|
+
description: "CSS Grid layout container",
|
|
283
|
+
selectors: [".grid"],
|
|
284
|
+
tags: ["layout", "columns", "css-grid"],
|
|
285
|
+
category: "layout"
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
id: "grid-cols",
|
|
289
|
+
name: "Grid Columns",
|
|
290
|
+
description: "Fixed column count grids",
|
|
291
|
+
selectors: [".grid-cols-1", ".grid-cols-2", ".grid-cols-3", ".grid-cols-4", ".grid-cols-6"],
|
|
292
|
+
tags: ["columns", "fixed", "grid"],
|
|
293
|
+
category: "layout"
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
id: "grid-auto",
|
|
297
|
+
name: "Auto-fit Grid",
|
|
298
|
+
description: "Responsive auto-fit grid with minimum widths",
|
|
299
|
+
selectors: [".grid-auto-sm", ".grid-auto-md", ".grid-auto-lg", ".grid-auto-xl"],
|
|
300
|
+
tags: ["responsive", "auto-fit", "fluid"],
|
|
301
|
+
category: "layout"
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
id: "flex",
|
|
305
|
+
name: "Flex Container",
|
|
306
|
+
description: "Flexbox layout with direction and wrap modifiers",
|
|
307
|
+
selectors: [".flex", ".flex-wrap", ".flex-col", ".flex-row"],
|
|
308
|
+
tags: ["flexbox", "layout", "alignment"],
|
|
309
|
+
category: "layout"
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
id: "grow",
|
|
313
|
+
name: "Flex Grow",
|
|
314
|
+
description: "Fill remaining flex space",
|
|
315
|
+
selectors: [".grow"],
|
|
316
|
+
tags: ["flex", "expand", "fill"],
|
|
317
|
+
category: "layout"
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
id: "stack",
|
|
321
|
+
name: "Stack",
|
|
322
|
+
description: "Vertical flex layout with predefined gaps",
|
|
323
|
+
selectors: [".stack-sm", ".stack-md", ".stack-lg", ".stack-xl"],
|
|
324
|
+
tags: ["vertical", "spacing", "column"],
|
|
325
|
+
category: "layout"
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
id: "gap",
|
|
329
|
+
name: "Gap",
|
|
330
|
+
description: "Spacing between flex/grid children",
|
|
331
|
+
selectors: [".gap-0", ".gap-xs", ".gap-sm", ".gap-md", ".gap-lg", ".gap-xl"],
|
|
332
|
+
tags: ["spacing", "margin", "gutters"],
|
|
333
|
+
category: "spacing"
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
id: "items",
|
|
337
|
+
name: "Items Alignment",
|
|
338
|
+
description: "Cross-axis alignment for flex/grid",
|
|
339
|
+
selectors: [".items-start", ".items-center", ".items-end", ".items-stretch", ".items-baseline"],
|
|
340
|
+
tags: ["alignment", "vertical", "cross-axis"],
|
|
341
|
+
category: "alignment"
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
id: "justify",
|
|
345
|
+
name: "Justify Content",
|
|
346
|
+
description: "Main-axis alignment for flex/grid",
|
|
347
|
+
selectors: [".justify-start", ".justify-center", ".justify-end", ".justify-between", ".justify-around", ".justify-evenly"],
|
|
348
|
+
tags: ["alignment", "horizontal", "main-axis"],
|
|
349
|
+
category: "alignment"
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
id: "max-width",
|
|
353
|
+
name: "Max-Width",
|
|
354
|
+
description: "Content width constraints",
|
|
355
|
+
selectors: [".max-w-sm", ".max-w-md", ".max-w-lg", ".max-w-xl"],
|
|
356
|
+
tags: ["width", "constraint", "readable"],
|
|
357
|
+
category: "sizing"
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
id: "section",
|
|
361
|
+
name: "Section Spacing",
|
|
362
|
+
description: "Vertical padding for content sections",
|
|
363
|
+
selectors: [".section", ".section-lg"],
|
|
364
|
+
tags: ["spacing", "vertical", "padding"],
|
|
365
|
+
category: "spacing"
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
id: "mobile-stack",
|
|
369
|
+
name: "Mobile Stack",
|
|
370
|
+
description: "Stack on mobile, row on desktop",
|
|
371
|
+
selectors: [".mobile-stack"],
|
|
372
|
+
tags: ["responsive", "mobile", "breakpoint"],
|
|
373
|
+
category: "responsive"
|
|
374
|
+
}
|
|
375
|
+
],
|
|
376
|
+
|
|
377
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
378
|
+
// UTILITIES (Low-level single-purpose classes)
|
|
379
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
380
|
+
utilities: {
|
|
381
|
+
text: {
|
|
382
|
+
alignment: [".text-left", ".text-center", ".text-right"],
|
|
383
|
+
color: [".text-muted", ".text-primary", ".text-success", ".text-warning", ".text-danger", ".text-info"],
|
|
384
|
+
overflow: [".truncate"]
|
|
385
|
+
},
|
|
386
|
+
backdrop: {
|
|
387
|
+
base: [".backdrop"],
|
|
388
|
+
variants: [".backdrop-light", ".backdrop-dark"],
|
|
389
|
+
blur: [".backdrop-blur-sm", ".backdrop-blur-md", ".backdrop-blur-lg"]
|
|
390
|
+
},
|
|
391
|
+
shadow: {
|
|
392
|
+
scale: [".shadow-sm", ".shadow-base", ".shadow-md", ".shadow-lg", ".shadow-xl", ".shadow-inner", ".shadow-none"]
|
|
393
|
+
},
|
|
394
|
+
border: {
|
|
395
|
+
gradient: [".border-gradient", ".border-gradient-primary", ".border-gradient-accent", ".border-gradient-secondary", ".border-gradient-soft", ".border-gradient-medium", ".border-gradient-strong"],
|
|
396
|
+
glow: [".border-glow", ".border-glow-sm", ".border-glow-lg", ".border-glow-primary", ".border-glow-accent", ".border-glow-success", ".border-glow-warning", ".border-glow-danger"],
|
|
397
|
+
combined: [".border-gradient-glow"]
|
|
398
|
+
},
|
|
399
|
+
media: {
|
|
400
|
+
image: [".img-gallery", ".img-rounded-sm", ".img-rounded-md", ".img-rounded-lg", ".img-rounded-xl", ".img-rounded-full", ".img-inline"],
|
|
401
|
+
video: [".video-responsive"],
|
|
402
|
+
figure: [".figure-responsive"]
|
|
403
|
+
},
|
|
404
|
+
effects: {
|
|
405
|
+
glass: [".liquid-glass"]
|
|
406
|
+
}
|
|
407
|
+
},
|
|
408
|
+
|
|
409
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
410
|
+
// RESPONSIVE UTILITIES (Breakpoint-prefixed)
|
|
411
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
412
|
+
responsive: {
|
|
413
|
+
prefixes: ["sm", "md", "lg"],
|
|
414
|
+
utilities: {
|
|
415
|
+
grid: [":grid-cols-2", ":grid-cols-3", ":grid-cols-4"],
|
|
416
|
+
flex: [":flex-row"],
|
|
417
|
+
text: [":text-sm", ":text-lg", ":text-xl"],
|
|
418
|
+
spacing: [":p-6", ":p-8", ":p-12", ":gap-6", ":gap-8", ":gap-12"],
|
|
419
|
+
width: [":w-1/2", ":w-1/3", ":w-1/4"],
|
|
420
|
+
display: [":hidden", ":block"]
|
|
421
|
+
}
|
|
422
|
+
},
|
|
423
|
+
|
|
424
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
425
|
+
// ENHANCEMENTS (Progressive enhancement selectors)
|
|
426
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
427
|
+
enhancements: [
|
|
428
|
+
{
|
|
429
|
+
id: "dropdown",
|
|
430
|
+
selector: "nav[data-dropdown]",
|
|
431
|
+
description: "Dropdown menu from nav element",
|
|
432
|
+
tags: ["menu", "interactive", "navigation"]
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
id: "toggle",
|
|
436
|
+
selector: "label[data-toggle]",
|
|
437
|
+
description: "Toggle switch from checkbox",
|
|
438
|
+
tags: ["switch", "boolean", "form"]
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
id: "range",
|
|
442
|
+
selector: 'input[type="range"]',
|
|
443
|
+
description: "Enhanced range slider with output",
|
|
444
|
+
tags: ["slider", "input", "form"]
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
id: "required",
|
|
448
|
+
selector: "form [required]",
|
|
449
|
+
description: "Required field asterisk indicator",
|
|
450
|
+
tags: ["validation", "form", "accessibility"]
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
id: "open-group",
|
|
454
|
+
selector: "fieldset[role=group][data-open]",
|
|
455
|
+
description: "Editable checkbox/radio group",
|
|
456
|
+
tags: ["form", "dynamic", "editable"]
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
id: "working-button",
|
|
460
|
+
selector: "button.btn-working, a.btn-working",
|
|
461
|
+
description: "Button with loading spinner",
|
|
462
|
+
tags: ["loading", "async", "feedback"]
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
id: "labeled-divider",
|
|
466
|
+
selector: "hr[data-content]",
|
|
467
|
+
description: "Horizontal rule with centered label",
|
|
468
|
+
tags: ["divider", "separator", "text"]
|
|
469
|
+
}
|
|
470
|
+
],
|
|
471
|
+
|
|
472
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
473
|
+
// SEMANTIC CATEGORIES (For correlation and search)
|
|
474
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
475
|
+
categories: {
|
|
476
|
+
feedback: {
|
|
477
|
+
description: "User feedback and status indicators",
|
|
478
|
+
primitives: ["alert", "badge"],
|
|
479
|
+
components: ["pds-toaster"]
|
|
480
|
+
},
|
|
481
|
+
form: {
|
|
482
|
+
description: "Form inputs and controls",
|
|
483
|
+
primitives: ["button", "fieldset", "label-field", "form"],
|
|
484
|
+
components: ["pds-upload", "pds-jsonform", "pds-richtext", "pds-calendar"]
|
|
485
|
+
},
|
|
486
|
+
layout: {
|
|
487
|
+
description: "Page structure and content arrangement",
|
|
488
|
+
patterns: ["container", "grid", "flex", "stack", "section"],
|
|
489
|
+
components: ["pds-splitpanel", "pds-scrollrow"]
|
|
490
|
+
},
|
|
491
|
+
navigation: {
|
|
492
|
+
description: "Navigation and routing",
|
|
493
|
+
primitives: ["navigation"],
|
|
494
|
+
components: ["pds-tabstrip", "pds-drawer"]
|
|
495
|
+
},
|
|
496
|
+
media: {
|
|
497
|
+
description: "Images, icons, and visual content",
|
|
498
|
+
primitives: ["icon", "figure", "gallery"],
|
|
499
|
+
components: ["pds-icon"]
|
|
500
|
+
},
|
|
501
|
+
overlay: {
|
|
502
|
+
description: "Modal and overlay content",
|
|
503
|
+
primitives: ["dialog"],
|
|
504
|
+
components: ["pds-drawer"]
|
|
505
|
+
},
|
|
506
|
+
data: {
|
|
507
|
+
description: "Data display and tables",
|
|
508
|
+
primitives: ["table"]
|
|
509
|
+
},
|
|
510
|
+
theming: {
|
|
511
|
+
description: "Colors, surfaces, and visual theming",
|
|
512
|
+
primitives: ["surface"]
|
|
513
|
+
}
|
|
514
|
+
},
|
|
515
|
+
|
|
516
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
517
|
+
// STYLE METADATA
|
|
518
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
519
|
+
styles: {
|
|
520
|
+
typography: ["headings", "body", "code", "links"],
|
|
521
|
+
icons: { source: "svg", sets: ["core", "brand"] },
|
|
522
|
+
interactive: ["focus", "hover", "active", "disabled"],
|
|
523
|
+
states: ["success", "warning", "danger", "info", "muted"]
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
528
|
+
// HELPER FUNCTIONS
|
|
529
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
530
|
+
|
|
531
|
+
// Safe matches with try/catch for invalid selectors or environments without .matches
|
|
532
|
+
function tryMatches(el, selector) {
|
|
533
|
+
if (!el || !selector) return false;
|
|
534
|
+
try {
|
|
535
|
+
return el.matches(selector);
|
|
536
|
+
} catch (e) {
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
function safeClosest(el, selector) {
|
|
542
|
+
if (!el || !selector || !el.closest) return null;
|
|
543
|
+
try {
|
|
544
|
+
return el.closest(selector);
|
|
545
|
+
} catch (e) {
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Find component for an element using the ontology
|
|
552
|
+
* @param {HTMLElement} startEl - Starting element to search from
|
|
553
|
+
* @param {Object} options - Search options
|
|
554
|
+
* @param {number} options.maxDepth - Maximum depth to traverse (default: 5)
|
|
555
|
+
* @returns {Object|null} Component info or null
|
|
556
|
+
*/
|
|
557
|
+
export function findComponentForElement(startEl, { maxDepth = 5 } = {}) {
|
|
558
|
+
if (!startEl) return null;
|
|
559
|
+
if (startEl.closest && startEl.closest('.showcase-toc')) return null;
|
|
560
|
+
|
|
561
|
+
let current = startEl;
|
|
562
|
+
let depth = 0;
|
|
563
|
+
|
|
564
|
+
while (current && depth < maxDepth) {
|
|
565
|
+
depth++;
|
|
566
|
+
|
|
567
|
+
// never traverse past the showcase
|
|
568
|
+
if (current.tagName === 'DS-SHOWCASE') return null;
|
|
569
|
+
|
|
570
|
+
// skip the section wrapper and continue climbing
|
|
571
|
+
if (current.classList && current.classList.contains('showcase-section')) {
|
|
572
|
+
current = current.parentElement;
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// 1) progressive enhancements
|
|
577
|
+
for (const enh of PDS.ontology.enhancements) {
|
|
578
|
+
const sel = enh.selector || enh;
|
|
579
|
+
if (tryMatches(current, sel)) {
|
|
580
|
+
return { element: current, componentType: 'enhanced-component', displayName: enh.description || sel, id: enh.id };
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// 2) Fieldset role groups
|
|
585
|
+
if (current.tagName === 'FIELDSET') {
|
|
586
|
+
const role = current.getAttribute('role');
|
|
587
|
+
if (role === 'group' || role === 'radiogroup') {
|
|
588
|
+
return { element: current, componentType: 'form-group', displayName: role === 'radiogroup' ? 'radio group' : 'form group' };
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// 3) label+input
|
|
593
|
+
if (current.tagName === 'LABEL') {
|
|
594
|
+
if (current.querySelector && current.querySelector('input,select,textarea')) {
|
|
595
|
+
return { element: current, componentType: 'form-control', displayName: 'label with input' };
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
const labelAncestor = current.closest ? current.closest('label') : null;
|
|
599
|
+
if (labelAncestor && labelAncestor.querySelector && labelAncestor.querySelector('input,select,textarea')) {
|
|
600
|
+
return { element: labelAncestor, componentType: 'form-control', displayName: 'label with input' };
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// 4) primitives
|
|
604
|
+
for (const prim of PDS.ontology.primitives) {
|
|
605
|
+
// handle each selector safely, support wildcard class prefix like .icon-*
|
|
606
|
+
for (const sel of prim.selectors || []) {
|
|
607
|
+
const s = String(sel || '').trim();
|
|
608
|
+
|
|
609
|
+
// Wildcard class prefix handling (e.g., .icon-*)
|
|
610
|
+
if (s.includes('*')) {
|
|
611
|
+
// Only support simple class wildcard like .prefix-*
|
|
612
|
+
if (s.startsWith('.')) {
|
|
613
|
+
const prefix = s.slice(1).replace(/\*/g, '');
|
|
614
|
+
if (current.classList && Array.from(current.classList).some((c) => c.startsWith(prefix))) {
|
|
615
|
+
return { element: current, componentType: 'pds-primitive', displayName: prim.name || prim.id, id: prim.id, tags: prim.tags };
|
|
616
|
+
}
|
|
617
|
+
// Also try to find an ancestor with such a class (but do not use closest with wildcard)
|
|
618
|
+
let ancestor = current.parentElement;
|
|
619
|
+
let levels = 0;
|
|
620
|
+
while (ancestor && levels < maxDepth) {
|
|
621
|
+
if (ancestor.classList && Array.from(ancestor.classList).some((c) => c.startsWith(prefix)) && ancestor.tagName !== 'DS-SHOWCASE') {
|
|
622
|
+
return { element: ancestor, componentType: 'pds-primitive', displayName: prim.name || prim.id, id: prim.id, tags: prim.tags };
|
|
623
|
+
}
|
|
624
|
+
ancestor = ancestor.parentElement;
|
|
625
|
+
levels++;
|
|
626
|
+
}
|
|
627
|
+
continue;
|
|
628
|
+
}
|
|
629
|
+
// unsupported wildcard pattern - skip
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// Normal selector: try matches, then safeClosest
|
|
634
|
+
if (tryMatches(current, s)) {
|
|
635
|
+
return { element: current, componentType: 'pds-primitive', displayName: prim.name || prim.id, id: prim.id, tags: prim.tags };
|
|
636
|
+
}
|
|
637
|
+
const ancestor = safeClosest(current, s);
|
|
638
|
+
if (ancestor && ancestor.tagName !== 'DS-SHOWCASE') {
|
|
639
|
+
return { element: ancestor, componentType: 'pds-primitive', displayName: prim.name || prim.id, id: prim.id, tags: prim.tags };
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// class prefix fallback for selectors that are like .icon-* written differently
|
|
644
|
+
if (current.classList) {
|
|
645
|
+
const clsList = Array.from(current.classList);
|
|
646
|
+
for (const s of prim.selectors || []) {
|
|
647
|
+
if (typeof s === 'string' && s.includes('*') && s.startsWith('.')) {
|
|
648
|
+
const prefix = s.slice(1).replace(/\*/g, '');
|
|
649
|
+
if (clsList.some((c) => c.startsWith(prefix))) {
|
|
650
|
+
return { element: current, componentType: 'pds-primitive', displayName: prim.name || prim.id, id: prim.id, tags: prim.tags };
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// 4.5) layout patterns - check before going higher in tree
|
|
658
|
+
for (const layout of PDS.ontology.layoutPatterns || []) {
|
|
659
|
+
for (const sel of layout.selectors || []) {
|
|
660
|
+
const s = String(sel || '').trim();
|
|
661
|
+
|
|
662
|
+
// Wildcard handling for gap-*, items-*, etc.
|
|
663
|
+
if (s.includes('*')) {
|
|
664
|
+
if (s.startsWith('.')) {
|
|
665
|
+
const prefix = s.slice(1).replace(/\*/g, '');
|
|
666
|
+
if (current.classList && Array.from(current.classList).some((c) => c.startsWith(prefix))) {
|
|
667
|
+
return { element: current, componentType: 'layout-pattern', displayName: layout.name || layout.id, id: layout.id, tags: layout.tags };
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// Normal selector
|
|
674
|
+
if (tryMatches(current, s)) {
|
|
675
|
+
return { element: current, componentType: 'layout-pattern', displayName: layout.name || layout.id, id: layout.id, tags: layout.tags };
|
|
676
|
+
}
|
|
677
|
+
const ancestor = safeClosest(current, s);
|
|
678
|
+
if (ancestor && ancestor.tagName !== 'DS-SHOWCASE') {
|
|
679
|
+
return { element: ancestor, componentType: 'layout-pattern', displayName: layout.name || layout.id, id: layout.id, tags: layout.tags };
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// 5) web components
|
|
685
|
+
if (current.tagName && current.tagName.includes('-')) {
|
|
686
|
+
const tagName = current.tagName.toLowerCase();
|
|
687
|
+
const comp = PDS.ontology.components.find(c => c.selectors.includes(tagName));
|
|
688
|
+
return {
|
|
689
|
+
element: current,
|
|
690
|
+
componentType: 'web-component',
|
|
691
|
+
displayName: comp?.name || tagName,
|
|
692
|
+
id: comp?.id || tagName,
|
|
693
|
+
tags: comp?.tags
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// 6) button/icon
|
|
698
|
+
if (current.tagName === 'BUTTON') {
|
|
699
|
+
const hasIcon = current.querySelector && current.querySelector('pds-icon');
|
|
700
|
+
return { element: current, componentType: 'button', displayName: hasIcon ? 'button with icon' : 'button', id: 'button' };
|
|
701
|
+
}
|
|
702
|
+
if (tryMatches(current, 'pds-icon') || (current.closest && current.closest('pds-icon'))) {
|
|
703
|
+
const el = tryMatches(current, 'pds-icon') ? current : current.closest('pds-icon');
|
|
704
|
+
return { element: el, componentType: 'icon', displayName: `pds-icon (${el.getAttribute && el.getAttribute('icon') || 'unknown'})`, id: 'pds-icon' };
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// 7) nav dropdown
|
|
708
|
+
if (tryMatches(current, 'nav[data-dropdown]') || (current.closest && current.closest('nav[data-dropdown]'))) {
|
|
709
|
+
const el = tryMatches(current, 'nav[data-dropdown]') ? current : current.closest('nav[data-dropdown]');
|
|
710
|
+
return { element: el, componentType: 'navigation', displayName: 'dropdown menu', id: 'dropdown' };
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// climb
|
|
714
|
+
current = current.parentElement;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
return null;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* Get all CSS selectors from the ontology
|
|
722
|
+
* @returns {string[]} Array of all selectors
|
|
723
|
+
*/
|
|
724
|
+
export function getAllSelectors() {
|
|
725
|
+
const s = [];
|
|
726
|
+
for (const p of PDS.ontology.primitives) s.push(...(p.selectors || []));
|
|
727
|
+
for (const c of PDS.ontology.components) s.push(...(c.selectors || []));
|
|
728
|
+
for (const l of PDS.ontology.layoutPatterns || []) s.push(...(l.selectors || []));
|
|
729
|
+
return Array.from(new Set(s));
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* Search the ontology by tag, name, or category
|
|
734
|
+
* @param {string} query - Search term
|
|
735
|
+
* @param {Object} options - Search options
|
|
736
|
+
* @returns {Object[]} Matching items
|
|
737
|
+
*/
|
|
738
|
+
export function searchOntology(query, options = {}) {
|
|
739
|
+
const q = query.toLowerCase();
|
|
740
|
+
const results = [];
|
|
741
|
+
|
|
742
|
+
const searchIn = (items, type) => {
|
|
743
|
+
for (const item of items) {
|
|
744
|
+
const matches =
|
|
745
|
+
item.id?.toLowerCase().includes(q) ||
|
|
746
|
+
item.name?.toLowerCase().includes(q) ||
|
|
747
|
+
item.description?.toLowerCase().includes(q) ||
|
|
748
|
+
item.tags?.some(t => t.toLowerCase().includes(q)) ||
|
|
749
|
+
item.category?.toLowerCase().includes(q) ||
|
|
750
|
+
item.selectors?.some(s => s.toLowerCase().includes(q));
|
|
751
|
+
|
|
752
|
+
if (matches) {
|
|
753
|
+
results.push({ ...item, type });
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
};
|
|
757
|
+
|
|
758
|
+
if (!options.type || options.type === 'primitive') {
|
|
759
|
+
searchIn(ontology.primitives, 'primitive');
|
|
760
|
+
}
|
|
761
|
+
if (!options.type || options.type === 'component') {
|
|
762
|
+
searchIn(ontology.components, 'component');
|
|
763
|
+
}
|
|
764
|
+
if (!options.type || options.type === 'layout') {
|
|
765
|
+
searchIn(ontology.layoutPatterns, 'layout');
|
|
766
|
+
}
|
|
767
|
+
if (!options.type || options.type === 'enhancement') {
|
|
768
|
+
searchIn(ontology.enhancements, 'enhancement');
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
return results;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
/**
|
|
775
|
+
* Get items by category
|
|
776
|
+
* @param {string} category - Category name
|
|
777
|
+
* @returns {Object} Items grouped by type
|
|
778
|
+
*/
|
|
779
|
+
export function getByCategory(category) {
|
|
780
|
+
const cat = category.toLowerCase();
|
|
781
|
+
return {
|
|
782
|
+
primitives: ontology.primitives.filter(p => p.category === cat),
|
|
783
|
+
components: ontology.components.filter(c => c.category === cat),
|
|
784
|
+
layouts: ontology.layoutPatterns.filter(l => l.category === cat)
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
/**
|
|
789
|
+
* Get all available tags
|
|
790
|
+
* @returns {string[]} Sorted unique tags
|
|
791
|
+
*/
|
|
792
|
+
export function getAllTags() {
|
|
793
|
+
const tags = new Set();
|
|
794
|
+
|
|
795
|
+
ontology.primitives.forEach(p => p.tags?.forEach(t => tags.add(t)));
|
|
796
|
+
ontology.components.forEach(c => c.tags?.forEach(t => tags.add(t)));
|
|
797
|
+
ontology.layoutPatterns.forEach(l => l.tags?.forEach(t => tags.add(t)));
|
|
798
|
+
ontology.enhancements.forEach(e => e.tags?.forEach(t => tags.add(t)));
|
|
799
|
+
|
|
800
|
+
return Array.from(tags).sort();
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
export default ontology;
|