@getdom/studio 0.1.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.
Files changed (213) hide show
  1. package/LICENSE.md +109 -0
  2. package/README.md +44 -0
  3. package/SKILL.md +83 -0
  4. package/package.json +73 -0
  5. package/public/llms.txt +57 -0
  6. package/public/skills.sh +11 -0
  7. package/src/pages/_layout/componentCatalog.generated.js +4514 -0
  8. package/src/pages/_layout/componentInspector.js +60 -0
  9. package/src/pages/_layout/componentManager.js +192 -0
  10. package/src/pages/_layout/componentRuntimeRecords.js +49 -0
  11. package/src/pages/_layout/inspector/componentRegistry.js +639 -0
  12. package/src/pages/_layout/inspector/serialize.js +134 -0
  13. package/src/pages/_layout/inspector/useInspector.js +293 -0
  14. package/src/pages/components/accordion/DomAccordion.vue +39 -0
  15. package/src/pages/components/breadcrumbs/DomBreadcrumbs.vue +347 -0
  16. package/src/pages/components/button/DomButton.vue +132 -0
  17. package/src/pages/components/command-palette/DomCommandPalette.vue +482 -0
  18. package/src/pages/components/context-menu/DomContextMenu.vue +178 -0
  19. package/src/pages/components/dialog/DomDialog.vue +271 -0
  20. package/src/pages/components/dialog/DomDialogSchemaForm.vue +72 -0
  21. package/src/pages/components/dialog/DomDialogStack.vue +289 -0
  22. package/src/pages/components/dialog/useDialogs.js +253 -0
  23. package/src/pages/components/drawer/DomDrawer.vue +159 -0
  24. package/src/pages/components/dropdown/DomDropdown.vue +261 -0
  25. package/src/pages/components/icon-button/DomIconButton.vue +155 -0
  26. package/src/pages/components/lightbox/DomLightbox.vue +1561 -0
  27. package/src/pages/components/menu/DomMenu.vue +359 -0
  28. package/src/pages/components/menu/DomMenuItem.vue +233 -0
  29. package/src/pages/components/menu/DomMenuLabel.vue +19 -0
  30. package/src/pages/components/menu/DomMenuSeparator.vue +14 -0
  31. package/src/pages/components/menu/menuContext.js +11 -0
  32. package/src/pages/components/menu/menuPlacement.js +26 -0
  33. package/src/pages/components/menu/submenu.js +58 -0
  34. package/src/pages/components/pagination/DomPagination.vue +265 -0
  35. package/src/pages/components/playground/DomRenderer.vue +48 -0
  36. package/src/pages/components/popover/DomPopover.vue +244 -0
  37. package/src/pages/components/profile-menu/DomProfileMenu.vue +408 -0
  38. package/src/pages/components/profile-menu/DomProfileMenuItemContent.vue +45 -0
  39. package/src/pages/components/scroll-menu/DomScrollMenu.vue +430 -0
  40. package/src/pages/components/scroll-menu/DomScrollMenuItem.vue +212 -0
  41. package/src/pages/components/scroll-menu/scrollMenuContext.js +22 -0
  42. package/src/pages/components/splitter-panel/DomSplitterPanel.vue +283 -0
  43. package/src/pages/components/stepper/DomStepper.vue +386 -0
  44. package/src/pages/components/tabs/DomTabs.vue +149 -0
  45. package/src/pages/components/theme-switcher/DomThemeSwitcher.vue +226 -0
  46. package/src/pages/components/toast/DomToastItem.vue +52 -0
  47. package/src/pages/components/toast/DomToastStack.vue +768 -0
  48. package/src/pages/components/toast/useToasts.js +237 -0
  49. package/src/pages/components/toolbar/DomToolbar.vue +158 -0
  50. package/src/pages/components/tooltip/DomTooltip.vue +69 -0
  51. package/src/pages/components/tooltip/vDomTooltip.js +106 -0
  52. package/src/pages/components/tree-view/DomTreeView.vue +961 -0
  53. package/src/pages/components/tree-view/treeSchemas.js +129 -0
  54. package/src/pages/components/tree-view/treeUtils.js +228 -0
  55. package/src/pages/data/_shared/calculateVirtualWindow.js +101 -0
  56. package/src/pages/data/_shared/resourceRecord.js +29 -0
  57. package/src/pages/data/activity-timeline/DomActivityTimeline.vue +417 -0
  58. package/src/pages/data/agent-chat/DomAgentChatShell.vue +565 -0
  59. package/src/pages/data/agent-chat/DomAgentConversation.vue +737 -0
  60. package/src/pages/data/agent-chat/DomAgentConversationList.vue +319 -0
  61. package/src/pages/data/agent-chat/examples/agentChatMockApi.js +620 -0
  62. package/src/pages/data/agent-chat/examples/useAgentChatDemoStore.js +730 -0
  63. package/src/pages/data/data-grid/DataGridVirtualRows.vue +220 -0
  64. package/src/pages/data/data-grid/DomDataGrid.vue +1643 -0
  65. package/src/pages/data/document-editor/DomDocumentEditor.vue +3030 -0
  66. package/src/pages/data/document-editor/documentEditorCodeBlock.js +282 -0
  67. package/src/pages/data/document-editor/examples/documentEditorMockApi.js +272 -0
  68. package/src/pages/data/document-editor/examples/useDocumentEditorDemoStore.js +284 -0
  69. package/src/pages/data/filter-bar/DomFilterBar.vue +533 -0
  70. package/src/pages/data/kanban/DomKanban.vue +1703 -0
  71. package/src/pages/data/kanban/kanbanApi.js +80 -0
  72. package/src/pages/data/media-browser/DomMediaBrowser.vue +2344 -0
  73. package/src/pages/data/media-browser/examples/mediaBrowserMockApi.js +653 -0
  74. package/src/pages/data/media-browser/examples/useMediaBrowserDemoStore.js +1157 -0
  75. package/src/pages/data/month-calendar/DomMonthCalendar.vue +1718 -0
  76. package/src/pages/data/week-planner/DomWeekPlanner.vue +2308 -0
  77. package/src/pages/dev/code-block/DomCodeBlock.vue +263 -0
  78. package/src/pages/dev/json-viewer/DomJsonViewer.vue +962 -0
  79. package/src/pages/forms/_shared/DomFieldLoadingSpinner.vue +12 -0
  80. package/src/pages/forms/_shared/options.js +61 -0
  81. package/src/pages/forms/_shared/useOptionMenu.js +59 -0
  82. package/src/pages/forms/autocomplete/DomAutocomplete.vue +180 -0
  83. package/src/pages/forms/calendar/DomCalendar.vue +442 -0
  84. package/src/pages/forms/checkbox/DomCheckbox.vue +69 -0
  85. package/src/pages/forms/class-toggle-input/DomClassToggleInput.vue +316 -0
  86. package/src/pages/forms/code-input/DomCodeInput.vue +202 -0
  87. package/src/pages/forms/color-input/DomColorInput.vue +118 -0
  88. package/src/pages/forms/combobox/DomCombobox.vue +237 -0
  89. package/src/pages/forms/confirmation-code-input/DomConfirmationCodeInput.vue +345 -0
  90. package/src/pages/forms/date-picker/DomDatePicker.vue +299 -0
  91. package/src/pages/forms/date-time-picker/DomDateTimePicker.vue +630 -0
  92. package/src/pages/forms/email-input/DomEmailInput.vue +55 -0
  93. package/src/pages/forms/field/DomField.vue +267 -0
  94. package/src/pages/forms/field/fieldLayout.js +1 -0
  95. package/src/pages/forms/field/fieldProps.js +114 -0
  96. package/src/pages/forms/field/layouts/DomGridFieldLayout.vue +38 -0
  97. package/src/pages/forms/field/useField.js +343 -0
  98. package/src/pages/forms/field/validators.js +364 -0
  99. package/src/pages/forms/file-upload/DomFileUpload.vue +361 -0
  100. package/src/pages/forms/form/DomForm.vue +985 -0
  101. package/src/pages/forms/form/adapters/fieldBuilder.js +45 -0
  102. package/src/pages/forms/form/adapters/jsonSchema.js +264 -0
  103. package/src/pages/forms/form/adapters/shared.js +53 -0
  104. package/src/pages/forms/form/adapters/zod.js +235 -0
  105. package/src/pages/forms/form/formApi.js +38 -0
  106. package/src/pages/forms/form/formDefinition.js +392 -0
  107. package/src/pages/forms/form/schemaAdapter.js +54 -0
  108. package/src/pages/forms/icon-selector/DomIconSelector.vue +460 -0
  109. package/src/pages/forms/icon-selector/iconSelectorItems.js +490 -0
  110. package/src/pages/forms/input-group/DomInputGroup.vue +232 -0
  111. package/src/pages/forms/json-input/DomJsonInput.vue +227 -0
  112. package/src/pages/forms/json-list-input/DomJsonListInput.vue +206 -0
  113. package/src/pages/forms/listbox/DomListbox.vue +105 -0
  114. package/src/pages/forms/money-input/DomMoneyInput.vue +147 -0
  115. package/src/pages/forms/native-select/DomNativeSelect.vue +67 -0
  116. package/src/pages/forms/number-input/DomNumberInput.vue +47 -0
  117. package/src/pages/forms/password-input/DomPasswordInput.vue +218 -0
  118. package/src/pages/forms/password-input/pwnedPasswords.js +47 -0
  119. package/src/pages/forms/password-strength/DomPasswordStrength.vue +128 -0
  120. package/src/pages/forms/password-strength/passwordStrength.js +92 -0
  121. package/src/pages/forms/position-input/DomPositionInput.vue +83 -0
  122. package/src/pages/forms/radio-group/DomRadioGroup.vue +102 -0
  123. package/src/pages/forms/range-input/DomRangeInput.vue +296 -0
  124. package/src/pages/forms/select/DomSelect.vue +479 -0
  125. package/src/pages/forms/select-input/DomSelectInput.vue +155 -0
  126. package/src/pages/forms/tag-combobox/DomTagCombobox.vue +358 -0
  127. package/src/pages/forms/text-input/DomTextInput.vue +48 -0
  128. package/src/pages/forms/textarea-composer/DomTextareaComposer.vue +234 -0
  129. package/src/pages/forms/textarea-input/DomTextareaInput.vue +86 -0
  130. package/src/pages/forms/textarea-input/useTextareaAutosize.js +147 -0
  131. package/src/pages/forms/time-selector/DomTimeSelector.vue +389 -0
  132. package/src/pages/forms/time-selector/timeUtils.js +194 -0
  133. package/src/pages/forms/toggle/DomToggle.vue +158 -0
  134. package/src/pages/forms/toggle-button/DomToggleButton.vue +88 -0
  135. package/src/pages/forms/toggle-button-group/DomToggleButtonGroup.vue +340 -0
  136. package/src/pages/forms/url-input/DomUrlInput.vue +55 -0
  137. package/src/pages/forms/wysiwyg/DomWysiwyg.vue +204 -0
  138. package/src/pages/lib/css/color.js +245 -0
  139. package/src/pages/lib/headless/accordion.d.ts +7 -0
  140. package/src/pages/lib/headless/accordion.js +246 -0
  141. package/src/pages/lib/headless/autocomplete.d.ts +4 -0
  142. package/src/pages/lib/headless/autocomplete.js +33 -0
  143. package/src/pages/lib/headless/base.d.ts +25 -0
  144. package/src/pages/lib/headless/base.js +127 -0
  145. package/src/pages/lib/headless/checkbox.d.ts +19 -0
  146. package/src/pages/lib/headless/checkbox.js +99 -0
  147. package/src/pages/lib/headless/combobox.d.ts +7 -0
  148. package/src/pages/lib/headless/combobox.js +488 -0
  149. package/src/pages/lib/headless/dialog.d.ts +23 -0
  150. package/src/pages/lib/headless/dialog.js +384 -0
  151. package/src/pages/lib/headless/drawer.d.ts +21 -0
  152. package/src/pages/lib/headless/drawer.js +682 -0
  153. package/src/pages/lib/headless/dropdown.d.ts +19 -0
  154. package/src/pages/lib/headless/dropdown.js +412 -0
  155. package/src/pages/lib/headless/floating-effect.js +118 -0
  156. package/src/pages/lib/headless/floating.d.ts +34 -0
  157. package/src/pages/lib/headless/floating.js +382 -0
  158. package/src/pages/lib/headless/index.d.ts +19 -0
  159. package/src/pages/lib/headless/index.js +19 -0
  160. package/src/pages/lib/headless/listbox.d.ts +19 -0
  161. package/src/pages/lib/headless/listbox.js +126 -0
  162. package/src/pages/lib/headless/menu.d.ts +18 -0
  163. package/src/pages/lib/headless/menu.js +117 -0
  164. package/src/pages/lib/headless/popover-panel.d.ts +18 -0
  165. package/src/pages/lib/headless/popover-panel.js +309 -0
  166. package/src/pages/lib/headless/popover.d.ts +19 -0
  167. package/src/pages/lib/headless/popover.js +391 -0
  168. package/src/pages/lib/headless/radio-group.d.ts +19 -0
  169. package/src/pages/lib/headless/radio-group.js +100 -0
  170. package/src/pages/lib/headless/tabs.d.ts +18 -0
  171. package/src/pages/lib/headless/tabs.js +119 -0
  172. package/src/pages/lib/headless/toast.d.ts +13 -0
  173. package/src/pages/lib/headless/toast.js +65 -0
  174. package/src/pages/lib/headless/toggle.d.ts +19 -0
  175. package/src/pages/lib/headless/toggle.js +162 -0
  176. package/src/pages/lib/headless/tooltip-controller.d.ts +22 -0
  177. package/src/pages/lib/headless/tooltip-controller.js +549 -0
  178. package/src/pages/lib/headless/tooltip.d.ts +19 -0
  179. package/src/pages/lib/headless/tooltip.js +153 -0
  180. package/src/pages/lib/headless/transitions.d.ts +5 -0
  181. package/src/pages/lib/headless/transitions.js +89 -0
  182. package/src/pages/lib/vue/_internal/DomLiquidGlassSurface.vue +310 -0
  183. package/src/pages/lib/vue/_internal/liquidGlass.js +112 -0
  184. package/src/pages/lib/vue/_internal/liquidGlassConfig.js +10 -0
  185. package/src/pages/lib/vue/codeHighlighter.js +132 -0
  186. package/src/pages/lib/vue/floatingTeleportTarget.js +23 -0
  187. package/src/pages/lib/vue/index.d.ts +6806 -0
  188. package/src/pages/lib/vue/index.js +218 -0
  189. package/src/pages/lib/vue/useTheme.js +116 -0
  190. package/src/pages/mobile/action-sheet/DomActionSheet.vue +186 -0
  191. package/src/pages/mobile/bottom-nav/DomAppBottomNav.vue +94 -0
  192. package/src/pages/mobile/list-item/DomAppListItem.vue +90 -0
  193. package/src/pages/mobile/safe-area/DomSafeArea.vue +39 -0
  194. package/src/pages/mobile/shell/DomAppShell.vue +51 -0
  195. package/src/pages/mobile/stack/AppStackScreen.vue +63 -0
  196. package/src/pages/mobile/stack/DomAppStack.vue +711 -0
  197. package/src/pages/mobile/top-bar/DomAppTopBar.vue +67 -0
  198. package/src/pages/visual/alert/DomAlert.vue +363 -0
  199. package/src/pages/visual/avatar/DomAvatar.vue +110 -0
  200. package/src/pages/visual/avatar-stack/DomAvatarStack.vue +89 -0
  201. package/src/pages/visual/badge/DomBadge.vue +105 -0
  202. package/src/pages/visual/card/DomCard.vue +65 -0
  203. package/src/pages/visual/card-rail/DomCardRail.vue +99 -0
  204. package/src/pages/visual/empty-state/DomEmptyState.vue +88 -0
  205. package/src/pages/visual/progress/DomProgress.vue +212 -0
  206. package/src/pages/visual/progress/DomRadialProgress.vue +186 -0
  207. package/src/pages/visual/progress/DomSegmentedProgress.vue +350 -0
  208. package/src/pages/visual/skeleton/DomSkeleton.vue +174 -0
  209. package/src/pages/visual/spinner/DomSpinner.vue +122 -0
  210. package/src/pages/visual/status-pill/DomStatusPill.vue +75 -0
  211. package/src/pages/visual/text-diff/DomTextDiff.vue +577 -0
  212. package/src/pages/visual/text-diff/textDiff.js +300 -0
  213. package/src/style.css +446 -0
@@ -0,0 +1,60 @@
1
+ import { labelFromExportName, labelFromSlug } from './componentManager.js';
2
+
3
+ /**
4
+ * Expands a component record with display metadata used by docs and editors.
5
+ *
6
+ * @param {object} record Component discovery record.
7
+ * @returns {object} Component record with normalized docs, labels, and props.
8
+ */
9
+ export function inspectComponentRecord(record) {
10
+ const component = record.component;
11
+ const doc = getComponentDoc(record);
12
+ const studio = getStudioMeta(record);
13
+ return {
14
+ ...record,
15
+ doc,
16
+ studio,
17
+ label: doc.name || labelFromExportName(record.exportName) || labelFromSlug(record.slug),
18
+ badge: doc.nav?.badge || doc.badge || null,
19
+ icon: doc.nav?.icon || doc.icon || studio.icon || null,
20
+ order: doc.order ?? 100,
21
+ hidden: Boolean(doc.hidden),
22
+ navHidden: Boolean(doc.hidden || doc.nav?.hidden),
23
+ studioHidden: Boolean(doc.hidden || studio.hidden),
24
+ props: getComponentProps(component),
25
+ };
26
+ }
27
+
28
+ /**
29
+ * Reads documentation metadata from either a Vue component or catalog record.
30
+ *
31
+ * @param {object} value Vue component object or component catalog record.
32
+ * @returns {object} Documentation metadata.
33
+ */
34
+ export function getComponentDoc(value) {
35
+ return value?.__doc || value?.component?.__doc || value?.doc || {};
36
+ }
37
+
38
+ /**
39
+ * Reads Studio editor metadata from either a Vue component or catalog record.
40
+ *
41
+ * @param {object} value Vue component object or component catalog record.
42
+ * @returns {object} Studio metadata.
43
+ */
44
+ export function getStudioMeta(value) {
45
+ const doc = getComponentDoc(value);
46
+ return value?.__studio || value?.component?.__studio || value?.studio || doc.studio || {};
47
+ }
48
+
49
+ /**
50
+ * Normalizes Vue props from a component object for docs/editor inspection.
51
+ *
52
+ * @param {object} component Vue component object.
53
+ * @returns {object} Component props keyed by prop name.
54
+ */
55
+ export function getComponentProps(component) {
56
+ const props = component?.props;
57
+ if (!props) return {};
58
+ if (Array.isArray(props)) return Object.fromEntries(props.map((key) => [key, {}]));
59
+ return props;
60
+ }
@@ -0,0 +1,192 @@
1
+ import { componentCatalog } from './componentCatalog.generated.js';
2
+
3
+ const lazyComponentModules = import.meta.glob([
4
+ '../components/*/Dom*.vue',
5
+ '../data/*/Dom*.vue',
6
+ '../dev/*/Dom*.vue',
7
+ '../forms/*/Dom*.vue',
8
+ '../mobile/*/Dom*.vue',
9
+ '../visual/*/Dom*.vue',
10
+ '!../components/playground/DomRenderer.vue',
11
+ '!../components/toast/DomToastItem.vue',
12
+ '!../forms/_shared/Dom*.vue',
13
+ ], { import: 'default' });
14
+ const lazyComponentSourceModules = import.meta.glob([
15
+ '../components/*/Dom*.vue',
16
+ '../data/*/Dom*.vue',
17
+ '../dev/*/Dom*.vue',
18
+ '../forms/*/Dom*.vue',
19
+ '../mobile/*/Dom*.vue',
20
+ '../visual/*/Dom*.vue',
21
+ '!../components/playground/DomRenderer.vue',
22
+ '!../components/toast/DomToastItem.vue',
23
+ '!../forms/_shared/Dom*.vue',
24
+ ], { import: 'default', query: '?raw' });
25
+
26
+ export const componentSections = ['components', 'data', 'dev', 'forms', 'mobile', 'visual'];
27
+
28
+ /**
29
+ * Returns component records that are safe for app-shell navigation and search.
30
+ *
31
+ * These records intentionally contain metadata only. Component implementations
32
+ * and raw SFC source strings are resolved through lazy records or runtime-only
33
+ * discovery so ordinary routes do not preload the whole component catalogue.
34
+ *
35
+ * @returns {Array<object>} Lightweight component discovery records.
36
+ */
37
+ export function getComponentRecords() {
38
+ return componentCatalog.map(recordFromCatalogRecord);
39
+ }
40
+
41
+ /**
42
+ * Returns lazy loaders for generated component documentation routes.
43
+ *
44
+ * @returns {Array<object>} Component records with dynamic component and source loaders.
45
+ */
46
+ export function getLazyComponentRecords() {
47
+ return getComponentRecords()
48
+ .map((record) => ({
49
+ ...record,
50
+ loader: lazyComponentModules[record.path],
51
+ sourceLoader: lazyComponentSourceModules[record.path],
52
+ }))
53
+ .filter((record) => record.loader);
54
+ }
55
+
56
+ /**
57
+ * Finds the first metadata record for a public component route.
58
+ *
59
+ * @param {string} route Public route path.
60
+ * @returns {object|undefined} Matching component record when one exists.
61
+ */
62
+ export function getComponentRecordByRoute(route) {
63
+ return getComponentRecords().find((record) => record.route === route);
64
+ }
65
+
66
+ /**
67
+ * Builds legacy redirects for components that moved from /components to /forms.
68
+ *
69
+ * @returns {Array<{ from: string, to: string }>} Redirect records.
70
+ */
71
+ export function getFormRedirectRecords() {
72
+ return getLazyComponentRecords()
73
+ .filter((record) => record.section === 'forms')
74
+ .map((record) => ({
75
+ from: `/components/${record.slug}`,
76
+ to: record.route,
77
+ }));
78
+ }
79
+
80
+ /**
81
+ * Builds legacy redirects for components that moved from /components to /data.
82
+ *
83
+ * @returns {Array<{ from: string, to: string }>} Redirect records.
84
+ */
85
+ export function getDataRedirectRecords() {
86
+ return getLazyComponentRecords()
87
+ .filter((record) => record.section === 'data')
88
+ .map((record) => ({
89
+ from: `/components/${record.slug}`,
90
+ to: record.route,
91
+ }));
92
+ }
93
+
94
+ /**
95
+ * Builds legacy redirects for developer components from /components.
96
+ *
97
+ * @returns {Array<{ from: string, to: string }>} Redirect records.
98
+ */
99
+ export function getDevRedirectRecords() {
100
+ return getLazyComponentRecords()
101
+ .filter((record) => record.section === 'dev')
102
+ .map((record) => ({
103
+ from: `/components/${record.slug}`,
104
+ to: record.route,
105
+ }));
106
+ }
107
+
108
+ /**
109
+ * Converts a component section key into a readable navigation label.
110
+ *
111
+ * @param {string} section Section key.
112
+ * @returns {string} Human-readable section label.
113
+ */
114
+ export function labelFromSection(section) {
115
+ return {
116
+ components: 'Components',
117
+ data: 'Data',
118
+ dev: 'Dev',
119
+ forms: 'Forms',
120
+ mobile: 'Mobile',
121
+ visual: 'Visual',
122
+ }[section] || labelFromSlug(section);
123
+ }
124
+
125
+ /**
126
+ * Converts a URL slug into a title-cased label.
127
+ *
128
+ * @param {string} slug URL slug.
129
+ * @returns {string} Human-readable label.
130
+ */
131
+ export function labelFromSlug(slug) {
132
+ return slug
133
+ .split('-')
134
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
135
+ .join(' ');
136
+ }
137
+
138
+ /**
139
+ * Converts a component export name into a default display label.
140
+ *
141
+ * @param {string} exportName Component export name.
142
+ * @returns {string} Human-readable component label.
143
+ */
144
+ export function labelFromExportName(exportName) {
145
+ return labelFromSlug(
146
+ String(exportName || '')
147
+ .replace(/^Dom/, '')
148
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
149
+ .toLowerCase(),
150
+ );
151
+ }
152
+
153
+ /**
154
+ * Builds a stable hash anchor for secondary component records.
155
+ *
156
+ * @param {object} record Component record.
157
+ * @returns {string} URL hash anchor without the leading #.
158
+ */
159
+ export function componentAnchor(record) {
160
+ return String(record?.exportName || record?.slug || '')
161
+ .replace(/^Dom/, 'dom-')
162
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
163
+ .toLowerCase();
164
+ }
165
+
166
+ /**
167
+ * Infers the primary component export name for a component folder slug.
168
+ *
169
+ * @param {string} slug Component folder slug.
170
+ * @returns {string} Expected primary export name.
171
+ */
172
+ export function primaryExportNameForSlug(slug) {
173
+ return `Dom${slug
174
+ .split('-')
175
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
176
+ .join('')}`;
177
+ }
178
+
179
+ /**
180
+ * Normalizes a catalog module record into the shape expected by docs helpers.
181
+ *
182
+ * @param {object} record Static component catalog record.
183
+ * @returns {object} Component discovery record.
184
+ */
185
+ function recordFromCatalogRecord(record) {
186
+ const doc = record.doc || {};
187
+ return {
188
+ ...record,
189
+ doc,
190
+ studio: record.studio || doc.studio || {},
191
+ };
192
+ }
@@ -0,0 +1,49 @@
1
+ const eagerComponentModules = import.meta.glob([
2
+ '../components/*/Dom*.vue',
3
+ '../data/*/Dom*.vue',
4
+ '../dev/*/Dom*.vue',
5
+ '../forms/*/Dom*.vue',
6
+ '../mobile/*/Dom*.vue',
7
+ '../visual/*/Dom*.vue',
8
+ '!../components/playground/DomRenderer.vue',
9
+ '!../components/toast/DomToastItem.vue',
10
+ '!../forms/_shared/Dom*.vue',
11
+ ], { eager: true, import: 'default' });
12
+
13
+ /**
14
+ * Returns eager component records for editor surfaces that need real components.
15
+ *
16
+ * This module is intentionally separate from componentManager.js so ordinary
17
+ * routes, navigation, and search can stay metadata-only while the inspector and
18
+ * related-component docs can still inspect props and render components.
19
+ *
20
+ * @returns {Array<object>} Component records with live Vue component objects.
21
+ */
22
+ export function getRuntimeComponentRecords() {
23
+ return Object.entries(eagerComponentModules)
24
+ .map(([path, component]) => recordFromPath(path, component))
25
+ .filter(Boolean);
26
+ }
27
+
28
+ /**
29
+ * Converts an import.meta.glob key into a component discovery record.
30
+ *
31
+ * @param {string} path Glob key relative to this layout folder.
32
+ * @param {object} component Vue component object.
33
+ * @returns {object|null} Component record, or null for unrecognized paths.
34
+ */
35
+ function recordFromPath(path, component) {
36
+ const match = path.match(/^\.\.\/(components|data|dev|forms|mobile|visual)\/([^/]+)\/(Dom[^/]+)\.vue$/);
37
+ if (!match) return null;
38
+
39
+ const [, section, slug, exportName] = match;
40
+ return {
41
+ id: `${section}/${slug}`,
42
+ path,
43
+ section,
44
+ slug,
45
+ exportName,
46
+ route: `/${section}/${slug}`,
47
+ component,
48
+ };
49
+ }