@elytracms/studio 0.0.35 → 0.0.36

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 (56) hide show
  1. package/dist/components/assets/asset-selection.d.ts +1 -1
  2. package/dist/components/assets/asset-selection.js +2 -2
  3. package/dist/components/assets/asset-selection.js.map +1 -1
  4. package/dist/components/builder/clipboard-actions.js +1 -1
  5. package/dist/components/builder/clipboard-actions.js.map +1 -1
  6. package/dist/components/builder/composition-field-editor.js +7 -7
  7. package/dist/components/builder/composition-field-editor.js.map +1 -1
  8. package/dist/components/builder/inline-edit.js +4 -3
  9. package/dist/components/builder/inline-edit.js.map +1 -1
  10. package/dist/components/builder/insert-context.js +1 -1
  11. package/dist/components/builder/insert-context.js.map +1 -1
  12. package/dist/components/builder/layout-inspector.js +2 -2
  13. package/dist/components/builder/layout-inspector.js.map +1 -1
  14. package/dist/components/builder/node-factory.js +7 -7
  15. package/dist/components/builder/node-factory.js.map +1 -1
  16. package/dist/components/builder/page-tree.js +1 -1
  17. package/dist/components/builder/page-tree.js.map +1 -1
  18. package/dist/components/builder/property-inspector.js +2 -2
  19. package/dist/components/builder/property-inspector.js.map +1 -1
  20. package/dist/components/builder/reuse-context.js +2 -2
  21. package/dist/components/builder/reuse-context.js.map +1 -1
  22. package/dist/components/builder/reuse.js +5 -4
  23. package/dist/components/builder/reuse.js.map +1 -1
  24. package/dist/components/cms/cell.js +1 -1
  25. package/dist/components/cms/cell.js.map +1 -1
  26. package/dist/components/cms/editable-cell.js +4 -4
  27. package/dist/components/cms/editable-cell.js.map +1 -1
  28. package/dist/components/cms/field-control.js +9 -9
  29. package/dist/components/cms/field-control.js.map +1 -1
  30. package/dist/components/cms/relation-picker.d.ts +2 -2
  31. package/dist/components/cms/relation-picker.js +5 -5
  32. package/dist/components/cms/relation-picker.js.map +1 -1
  33. package/dist/components/components/component-detail.js +1 -1
  34. package/dist/components/components/component-detail.js.map +1 -1
  35. package/dist/components/components/components-index.js +1 -1
  36. package/dist/components/components/components-index.js.map +1 -1
  37. package/dist/components/components/registry-browser.js +2 -2
  38. package/dist/components/components/registry-browser.js.map +1 -1
  39. package/dist/components/extensions/extensions-view.js +1 -1
  40. package/dist/components/extensions/extensions-view.js.map +1 -1
  41. package/dist/lib/clipboard/paste-target.js +1 -1
  42. package/dist/lib/clipboard/paste-target.js.map +1 -1
  43. package/dist/lib/dnd/drop-rules.js +2 -2
  44. package/dist/lib/dnd/drop-rules.js.map +1 -1
  45. package/dist/lib/dnd/gap-drag.js +2 -2
  46. package/dist/lib/dnd/gap-drag.js.map +1 -1
  47. package/dist/lib/persona/labels.d.ts +2 -2
  48. package/dist/lib/persona/labels.js +3 -3
  49. package/dist/lib/persona/labels.js.map +1 -1
  50. package/dist/lib/references/reference-model.js +1 -1
  51. package/dist/lib/references/reference-model.js.map +1 -1
  52. package/dist/lib/registry/preview.js +15 -15
  53. package/dist/lib/registry/preview.js.map +1 -1
  54. package/dist/lib/registry/project-components.js +6 -13
  55. package/dist/lib/registry/project-components.js.map +1 -1
  56. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"relation-picker.js","sourceRoot":"","sources":["../../../src/components/cms/relation-picker.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Check, Search, X } from 'lucide-react'\nimport { useEffect, useState } from 'react'\nimport type { DocumentRef } from '@elytracms/core/cms-core'\nimport {\n Badge,\n Button,\n Code,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Input,\n Row,\n Spacer,\n Text,\n} from '@elytracms/studio/ui'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { useCollectionView } from '../collection-view/collection-view-context'\n\n/** Pick related document(s) from a target collection (brief §8.4, EC-074). */\nexport function RelationPicker({\n targetCollection,\n cardinality,\n value,\n open,\n onOpenChange,\n onChange,\n excludeIds,\n}: {\n targetCollection: string\n cardinality: 'one' | 'many'\n value: DocumentRef[]\n open: boolean\n onOpenChange: (open: boolean) => void\n onChange: (refs: DocumentRef[]) => void\n /**\n * Document ids to omit from the candidate list (EC-218): a `parent` self-relation\n * passes the editing document plus its descendants, so a page can never be set\n * as its own ancestor (which would form a cycle).\n */\n excludeIds?: ReadonlySet<string>\n}) {\n const source = useCollectionView()\n const [query, setQuery] = useState('')\n const [selected, setSelected] = useState<DocumentRef[]>(value)\n\n // Seed selection only on open transitions — `value` is a fresh array each\n // parent render, so depending on it would reset in-progress multi-selection.\n useEffect(() => {\n if (open) {\n setSelected(value)\n setQuery('')\n }\n }, [open])\n\n const candidates = source.referenceCandidates(targetCollection).filter((d) => {\n if (excludeIds?.has(d.id)) return false\n if (!query.trim()) return true\n return source.titleOf({ collection: targetCollection, id: d.id }).toLowerCase().includes(query.toLowerCase())\n })\n\n const isSelected = (id: string) => selected.some((r) => r.id === id)\n\n function toggle(id: string) {\n const ref: DocumentRef = { collection: targetCollection, id }\n if (cardinality === 'one') {\n setSelected([ref])\n onChange([ref])\n onOpenChange(false)\n return\n }\n setSelected((prev) => (isSelected(id) ? prev.filter((r) => r.id !== id) : [...prev, ref]))\n }\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-w-md\">\n <DialogHeader>\n <DialogTitle>\n {translate(cardinality === 'many' ? 'cms.relation.pickTitle.many' : 'cms.relation.pickTitle.one')}\n </DialogTitle>\n <DialogDescription>\n From <Code tone=\"muted\">{targetCollection}</Code>\n {cardinality === 'many' ? ` · ${translate('cms.relation.selectMultipleHint')}` : ''}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"relative\">\n <Search className=\"pointer-events-none absolute left-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground\" />\n <Input\n autoFocus\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder={translate('common.searchPlaceholder')}\n className=\"pl-8\"\n />\n </div>\n\n <div className=\"max-h-72 overflow-auto\">\n {candidates.length === 0 ? (\n <Text size=\"sm\" tone=\"muted\" className=\"p-3\">\n {translate('cms.relation.noDocuments', { collection: targetCollection })}\n </Text>\n ) : (\n candidates.map((doc) => {\n const title = source.titleOf({ collection: targetCollection, id: doc.id })\n const sel = isSelected(doc.id)\n return (\n <button\n key={doc.id}\n type=\"button\"\n onClick={() => toggle(doc.id)}\n className={cn(\n 'flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm transition-colors hover:bg-muted',\n sel && 'bg-accent text-accent-foreground',\n )}\n >\n <span className=\"min-w-0 flex-1 truncate font-medium\">{title}</span>\n <Code tone=\"muted\">{doc.id}</Code>\n {sel ? <Check className=\"size-4 text-primary\" /> : null}\n </button>\n )\n })\n )}\n </div>\n\n {value.length > 0 || cardinality === 'many' ? (\n <DialogFooter>\n <Row gap=\"2\" className=\"w-full\">\n {/* EC-246c: a way to CLEAR the relation from the picker — the only\n remove path for a cardinality-`one` relation edited inline in the\n list (the form field has its own per-row X). */}\n {value.length > 0 ? (\n <Button\n variant=\"ghost\"\n className=\"text-destructive hover:text-destructive\"\n data-testid=\"relation-remove\"\n onClick={() => {\n onChange([])\n onOpenChange(false)\n }}\n >\n <X /> {translate('common.remove')}\n </Button>\n ) : null}\n <Spacer />\n {cardinality === 'many' ? (\n <>\n <Badge variant=\"outline\">{translate('cms.relation.selectedCount', { count: selected.length })}</Badge>\n <Button variant=\"ghost\" onClick={() => onOpenChange(false)}>\n {translate('common.cancel')}\n </Button>\n <Button\n onClick={() => {\n onChange(selected)\n onOpenChange(false)\n }}\n >\n {translate('common.apply')}\n </Button>\n </>\n ) : null}\n </Row>\n </DialogFooter>\n ) : null}\n </DialogContent>\n </Dialog>\n )\n}\n"]}
1
+ {"version":3,"file":"relation-picker.js","sourceRoot":"","sources":["../../../src/components/cms/relation-picker.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Check, Search, X } from 'lucide-react'\nimport { useEffect, useState } from 'react'\nimport type { DocumentRef } from '@elytracms/core/cms-core'\nimport {\n Badge,\n Button,\n Code,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Input,\n Row,\n Spacer,\n Text,\n} from '@elytracms/studio/ui'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { useCollectionView } from '../collection-view/collection-view-context'\n\n/** Pick related document(s) from a target collection (brief §8.4, EC-074). */\nexport function RelationPicker({\n targetCollection,\n multiple,\n value,\n open,\n onOpenChange,\n onChange,\n excludeIds,\n}: {\n targetCollection: string\n multiple: boolean\n value: DocumentRef[]\n open: boolean\n onOpenChange: (open: boolean) => void\n onChange: (refs: DocumentRef[]) => void\n /**\n * Document ids to omit from the candidate list (EC-218): a `parent` self-relation\n * passes the editing document plus its descendants, so a page can never be set\n * as its own ancestor (which would form a cycle).\n */\n excludeIds?: ReadonlySet<string>\n}) {\n const source = useCollectionView()\n const [query, setQuery] = useState('')\n const [selected, setSelected] = useState<DocumentRef[]>(value)\n\n // Seed selection only on open transitions — `value` is a fresh array each\n // parent render, so depending on it would reset in-progress multi-selection.\n useEffect(() => {\n if (open) {\n setSelected(value)\n setQuery('')\n }\n }, [open])\n\n const candidates = source.referenceCandidates(targetCollection).filter((d) => {\n if (excludeIds?.has(d.id)) return false\n if (!query.trim()) return true\n return source.titleOf({ collection: targetCollection, id: d.id }).toLowerCase().includes(query.toLowerCase())\n })\n\n const isSelected = (id: string) => selected.some((r) => r.id === id)\n\n function toggle(id: string) {\n const ref: DocumentRef = { collection: targetCollection, id }\n if (!multiple) {\n setSelected([ref])\n onChange([ref])\n onOpenChange(false)\n return\n }\n setSelected((prev) => (isSelected(id) ? prev.filter((r) => r.id !== id) : [...prev, ref]))\n }\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-w-md\">\n <DialogHeader>\n <DialogTitle>\n {translate(multiple ? 'cms.relation.pickTitle.many' : 'cms.relation.pickTitle.one')}\n </DialogTitle>\n <DialogDescription>\n From <Code tone=\"muted\">{targetCollection}</Code>\n {multiple ? ` · ${translate('cms.relation.selectMultipleHint')}` : ''}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"relative\">\n <Search className=\"pointer-events-none absolute left-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground\" />\n <Input\n autoFocus\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder={translate('common.searchPlaceholder')}\n className=\"pl-8\"\n />\n </div>\n\n <div className=\"max-h-72 overflow-auto\">\n {candidates.length === 0 ? (\n <Text size=\"sm\" tone=\"muted\" className=\"p-3\">\n {translate('cms.relation.noDocuments', { collection: targetCollection })}\n </Text>\n ) : (\n candidates.map((doc) => {\n const title = source.titleOf({ collection: targetCollection, id: doc.id })\n const sel = isSelected(doc.id)\n return (\n <button\n key={doc.id}\n type=\"button\"\n onClick={() => toggle(doc.id)}\n className={cn(\n 'flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm transition-colors hover:bg-muted',\n sel && 'bg-accent text-accent-foreground',\n )}\n >\n <span className=\"min-w-0 flex-1 truncate font-medium\">{title}</span>\n <Code tone=\"muted\">{doc.id}</Code>\n {sel ? <Check className=\"size-4 text-primary\" /> : null}\n </button>\n )\n })\n )}\n </div>\n\n {value.length > 0 || multiple ? (\n <DialogFooter>\n <Row gap=\"2\" className=\"w-full\">\n {/* EC-246c: a way to CLEAR the relation from the picker — the only\n remove path for a cardinality-`one` relation edited inline in the\n list (the form field has its own per-row X). */}\n {value.length > 0 ? (\n <Button\n variant=\"ghost\"\n className=\"text-destructive hover:text-destructive\"\n data-testid=\"relation-remove\"\n onClick={() => {\n onChange([])\n onOpenChange(false)\n }}\n >\n <X /> {translate('common.remove')}\n </Button>\n ) : null}\n <Spacer />\n {multiple ? (\n <>\n <Badge variant=\"outline\">{translate('cms.relation.selectedCount', { count: selected.length })}</Badge>\n <Button variant=\"ghost\" onClick={() => onOpenChange(false)}>\n {translate('common.cancel')}\n </Button>\n <Button\n onClick={() => {\n onChange(selected)\n onOpenChange(false)\n }}\n >\n {translate('common.apply')}\n </Button>\n </>\n ) : null}\n </Row>\n </DialogFooter>\n ) : null}\n </DialogContent>\n </Dialog>\n )\n}\n"]}
@@ -25,7 +25,7 @@ export function ComponentDetail({ projectId, componentId, }) {
25
25
  return (_jsx("div", { className: "grid h-full place-items-center p-8", children: _jsxs(Stack, { gap: "3", align: "center", className: "max-w-sm text-center", children: [_jsx(Heading, { level: 2, size: "h2", children: translate('components.detail.notFound.title') }), _jsx(Text, { tone: "muted", children: translate('components.detail.notFound.body', { id: componentId }) }), _jsx(Link, { to: STUDIO_PROJECT_ROUTE, params: { projectId, _splat: studioPath.components() }, className: "text-sm text-primary hover:underline", children: translate('components.detail.notFound.back') })] }) }));
26
26
  }
27
27
  const status = componentStatus(studio, manifest);
28
- const namespace = isPrimitive(manifest.id) ? 'base.primitives' : 'project';
28
+ const namespace = isPrimitive(manifest.id) ? 'base' : 'project';
29
29
  return (_jsxs("div", { className: "mx-auto w-full max-w-4xl p-4 sm:p-6", children: [_jsxs(Link, { to: STUDIO_PROJECT_ROUTE, params: { projectId, _splat: studioPath.components() }, className: "mb-3 inline-flex items-center gap-1 text-xs text-muted-foreground transition-colors hover:text-foreground md:hidden", children: [_jsx(ArrowLeft, { className: "size-3.5" }), " ", translate('components.detail.allComponents')] }), _jsxs(Stack, { gap: "6", children: [_jsxs(Stack, { gap: "2", children: [_jsxs(Row, { gap: "2", wrap: true, children: [_jsx(Heading, { size: "display", children: manifest.title ?? manifest.id }), _jsx(Badge, { variant: namespace === 'project' ? 'primary' : 'outline', children: namespace }), manifest.category ? _jsx(Badge, { variant: "outline", children: manifest.category }) : null, _jsx(Spacer, {}), _jsx(ComponentStatusBadge, { status: status })] }), _jsx(Code, { tone: "muted", className: "w-fit", children: manifest.id }), manifest.description ? (_jsx(Text, { tone: "muted", className: "max-w-prose", children: manifest.description })) : null, status !== 'valid' ? (_jsx(Text, { size: "sm", className: status === 'invalid' ? 'text-destructive' : 'text-warning', children: statusDescription(status) })) : null] }), manifest.designTokens && manifest.designTokens.length > 0 ? (_jsxs(Stack, { gap: "1", children: [_jsx(Text, { size: "xs", tone: "muted", mono: true, children: translate('components.detail.designTokens') }), _jsx(Row, { gap: "1", wrap: true, children: manifest.designTokens.map((token) => (_jsx(Code, { tone: "muted", children: token }, token))) })] })) : null, _jsx(FixtureRunner, { manifest: manifest }, manifest.id), _jsx(FieldInspector, { manifest: manifest }), _jsx(ReferencesPanel, { projectId: projectId, target: { type: 'component', id: manifest.id } })] })] }));
30
30
  }
31
31
  //# sourceMappingURL=component-detail.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"component-detail.js","sourceRoot":"","sources":["../../../src/components/components/component-detail.tsx"],"names":[],"mappings":"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","sourcesContent":["import { ArrowLeft } from 'lucide-react'\nimport { isPrimitive } from '@elytracms/core/component-registry'\nimport { Link, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router'\nimport { componentStatus, getStudioRegistry } from '@elytracms/studio/lib/registry'\nimport {\n ComponentStatusBadge,\n statusDescription,\n} from '@elytracms/studio/components/components/component-status'\nimport { FieldInspector } from '@elytracms/studio/components/components/field-inspector'\nimport { FixtureRunner } from '@elytracms/studio/components/components/fixture-runner'\nimport { ReferencesPanel } from '@elytracms/studio/components/references/references-panel'\nimport { useSetBreadcrumb } from '@elytracms/studio/components/breadcrumb-context'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { Badge, Code, Heading, Row, Spacer, Stack, Text } from '@elytracms/studio/ui'\n\n/**\n * The component detail view (EC-223 Stage 6): manifest metadata, the field/slot\n * inspector, the fixture runner, and inbound references. Takes its ids as props\n * — the splat resolver sources `componentId` from the engine route table.\n */\nexport function ComponentDetail({\n projectId,\n componentId,\n}: {\n projectId: string\n componentId: string\n}) {\n const studio = getStudioRegistry()\n const manifest = studio.registry.getManifest(componentId)\n\n // EC-214: the component is the active record — name it in the global header\n // breadcrumb (under the Components section crumb).\n useSetBreadcrumb([{ label: manifest?.title ?? manifest?.id ?? componentId }])\n\n if (!manifest) {\n return (\n <div className=\"grid h-full place-items-center p-8\">\n <Stack gap=\"3\" align=\"center\" className=\"max-w-sm text-center\">\n <Heading level={2} size=\"h2\">\n {translate('components.detail.notFound.title')}\n </Heading>\n <Text tone=\"muted\">\n {translate('components.detail.notFound.body', { id: componentId })}\n </Text>\n <Link\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.components() }}\n className=\"text-sm text-primary hover:underline\"\n >\n {translate('components.detail.notFound.back')}\n </Link>\n </Stack>\n </div>\n )\n }\n\n const status = componentStatus(studio, manifest)\n const namespace = isPrimitive(manifest.id) ? 'base.primitives' : 'project'\n\n return (\n <div className=\"mx-auto w-full max-w-4xl p-4 sm:p-6\">\n <Link\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.components() }}\n className=\"mb-3 inline-flex items-center gap-1 text-xs text-muted-foreground transition-colors hover:text-foreground md:hidden\"\n >\n <ArrowLeft className=\"size-3.5\" /> {translate('components.detail.allComponents')}\n </Link>\n\n <Stack gap=\"6\">\n {/* Header */}\n <Stack gap=\"2\">\n <Row gap=\"2\" wrap>\n <Heading size=\"display\">{manifest.title ?? manifest.id}</Heading>\n <Badge variant={namespace === 'project' ? 'primary' : 'outline'}>{namespace}</Badge>\n {manifest.category ? <Badge variant=\"outline\">{manifest.category}</Badge> : null}\n <Spacer />\n <ComponentStatusBadge status={status} />\n </Row>\n <Code tone=\"muted\" className=\"w-fit\">\n {manifest.id}\n </Code>\n {manifest.description ? (\n <Text tone=\"muted\" className=\"max-w-prose\">\n {manifest.description}\n </Text>\n ) : null}\n {status !== 'valid' ? (\n <Text size=\"sm\" className={status === 'invalid' ? 'text-destructive' : 'text-warning'}>\n {statusDescription(status)}\n </Text>\n ) : null}\n </Stack>\n\n {/* Design tokens */}\n {manifest.designTokens && manifest.designTokens.length > 0 ? (\n <Stack gap=\"1\">\n <Text size=\"xs\" tone=\"muted\" mono>\n {translate('components.detail.designTokens')}\n </Text>\n <Row gap=\"1\" wrap>\n {manifest.designTokens.map((token) => (\n <Code key={token} tone=\"muted\">\n {token}\n </Code>\n ))}\n </Row>\n </Stack>\n ) : null}\n\n {/* Fixture runner — keyed so state resets when switching components. */}\n <FixtureRunner key={manifest.id} manifest={manifest} />\n\n {/* Field inspector */}\n <FieldInspector manifest={manifest} />\n\n {/* Where is this component used? (EC-172, inbound over the EC-155 index) */}\n <ReferencesPanel projectId={projectId} target={{ type: 'component', id: manifest.id }} />\n </Stack>\n </div>\n )\n}\n"]}
1
+ {"version":3,"file":"component-detail.js","sourceRoot":"","sources":["../../../src/components/components/component-detail.tsx"],"names":[],"mappings":"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","sourcesContent":["import { ArrowLeft } from 'lucide-react'\nimport { isPrimitive } from '@elytracms/core/component-registry'\nimport { Link, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router'\nimport { componentStatus, getStudioRegistry } from '@elytracms/studio/lib/registry'\nimport {\n ComponentStatusBadge,\n statusDescription,\n} from '@elytracms/studio/components/components/component-status'\nimport { FieldInspector } from '@elytracms/studio/components/components/field-inspector'\nimport { FixtureRunner } from '@elytracms/studio/components/components/fixture-runner'\nimport { ReferencesPanel } from '@elytracms/studio/components/references/references-panel'\nimport { useSetBreadcrumb } from '@elytracms/studio/components/breadcrumb-context'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { Badge, Code, Heading, Row, Spacer, Stack, Text } from '@elytracms/studio/ui'\n\n/**\n * The component detail view (EC-223 Stage 6): manifest metadata, the field/slot\n * inspector, the fixture runner, and inbound references. Takes its ids as props\n * — the splat resolver sources `componentId` from the engine route table.\n */\nexport function ComponentDetail({\n projectId,\n componentId,\n}: {\n projectId: string\n componentId: string\n}) {\n const studio = getStudioRegistry()\n const manifest = studio.registry.getManifest(componentId)\n\n // EC-214: the component is the active record — name it in the global header\n // breadcrumb (under the Components section crumb).\n useSetBreadcrumb([{ label: manifest?.title ?? manifest?.id ?? componentId }])\n\n if (!manifest) {\n return (\n <div className=\"grid h-full place-items-center p-8\">\n <Stack gap=\"3\" align=\"center\" className=\"max-w-sm text-center\">\n <Heading level={2} size=\"h2\">\n {translate('components.detail.notFound.title')}\n </Heading>\n <Text tone=\"muted\">\n {translate('components.detail.notFound.body', { id: componentId })}\n </Text>\n <Link\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.components() }}\n className=\"text-sm text-primary hover:underline\"\n >\n {translate('components.detail.notFound.back')}\n </Link>\n </Stack>\n </div>\n )\n }\n\n const status = componentStatus(studio, manifest)\n const namespace = isPrimitive(manifest.id) ? 'base' : 'project'\n\n return (\n <div className=\"mx-auto w-full max-w-4xl p-4 sm:p-6\">\n <Link\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.components() }}\n className=\"mb-3 inline-flex items-center gap-1 text-xs text-muted-foreground transition-colors hover:text-foreground md:hidden\"\n >\n <ArrowLeft className=\"size-3.5\" /> {translate('components.detail.allComponents')}\n </Link>\n\n <Stack gap=\"6\">\n {/* Header */}\n <Stack gap=\"2\">\n <Row gap=\"2\" wrap>\n <Heading size=\"display\">{manifest.title ?? manifest.id}</Heading>\n <Badge variant={namespace === 'project' ? 'primary' : 'outline'}>{namespace}</Badge>\n {manifest.category ? <Badge variant=\"outline\">{manifest.category}</Badge> : null}\n <Spacer />\n <ComponentStatusBadge status={status} />\n </Row>\n <Code tone=\"muted\" className=\"w-fit\">\n {manifest.id}\n </Code>\n {manifest.description ? (\n <Text tone=\"muted\" className=\"max-w-prose\">\n {manifest.description}\n </Text>\n ) : null}\n {status !== 'valid' ? (\n <Text size=\"sm\" className={status === 'invalid' ? 'text-destructive' : 'text-warning'}>\n {statusDescription(status)}\n </Text>\n ) : null}\n </Stack>\n\n {/* Design tokens */}\n {manifest.designTokens && manifest.designTokens.length > 0 ? (\n <Stack gap=\"1\">\n <Text size=\"xs\" tone=\"muted\" mono>\n {translate('components.detail.designTokens')}\n </Text>\n <Row gap=\"1\" wrap>\n {manifest.designTokens.map((token) => (\n <Code key={token} tone=\"muted\">\n {token}\n </Code>\n ))}\n </Row>\n </Stack>\n ) : null}\n\n {/* Fixture runner — keyed so state resets when switching components. */}\n <FixtureRunner key={manifest.id} manifest={manifest} />\n\n {/* Field inspector */}\n <FieldInspector manifest={manifest} />\n\n {/* Where is this component used? (EC-172, inbound over the EC-155 index) */}\n <ReferencesPanel projectId={projectId} target={{ type: 'component', id: manifest.id }} />\n </Stack>\n </div>\n )\n}\n"]}
@@ -31,7 +31,7 @@ export function ComponentsIndex({ projectId }) {
31
31
  return (_jsxs("div", { className: "mx-auto w-full max-w-4xl p-4 sm:p-6", children: [_jsx("div", { className: "mb-6 h-80 overflow-hidden rounded-lg border border-border md:hidden", children: _jsx(RegistryBrowser, { projectId: projectId }) }), _jsxs(Stack, { gap: "6", children: [_jsxs(Stack, { gap: "1", children: [_jsx(Heading, { size: "display", children: translate('components.index.title') }), _jsx(Text, { tone: "muted", children: translate('components.index.subtitle') })] }), _jsxs("div", { className: "grid gap-3 sm:grid-cols-3", children: [_jsx(StatCard, { label: translate('components.index.stat.total'), value: health.total, hint: translate('components.index.stat.totalHint', { primitives, projects }) }), _jsx(StatCard, { label: translate('components.index.stat.valid'), value: health.valid, tone: "success" }), _jsx(StatCard, { label: translate('components.index.stat.needAttention'), value: health.incompatible + health.invalid, tone: health.incompatible + health.invalid > 0 ? 'warning' : 'muted', hint: translate('components.index.stat.needAttentionHint', {
32
32
  incompatible: health.incompatible,
33
33
  invalid: health.invalid,
34
- }) })] }), _jsxs(Card, { className: "flex items-center gap-3 p-4", children: [_jsx("span", { className: "grid size-9 shrink-0 place-items-center rounded-lg bg-muted text-muted-foreground", children: _jsx(MousePointerClick, { className: "size-4" }) }), _jsx(Text, { size: "sm", tone: "muted", children: translate('components.index.pickHint') })] }), _jsxs(Panel, { children: [_jsxs(PanelHeader, { children: [_jsx(Blocks, { className: "size-4 text-muted-foreground" }), _jsx(Text, { size: "sm", weight: "semibold", children: translate('components.index.guide.title') }), _jsx(Spacer, {}), _jsx(Badge, { variant: "outline", children: translate('components.index.guide.badge') })] }), _jsxs(Stack, { gap: "3", className: "p-4", children: [_jsxs(Text, { size: "sm", tone: "muted", children: ["Project code owns its components. Register a manifest under the", ' ', _jsx(Code, { tone: "primary", children: "project.*" }), " namespace (platform primitives live under", ' ', _jsx(Code, { tone: "muted", children: "base.primitives.*" }), "). The manifest declares prop schemas, defaults, inspector controls, binding permissions, slots, and preview fixtures."] }), _jsx("pre", { className: "overflow-x-auto rounded-lg border border-border bg-muted/40 p-3 font-mono text-xs leading-relaxed text-foreground/90", children: REGISTER_EXAMPLE }), _jsx(Text, { size: "xs", tone: "subtle", children: translate('components.index.guide.fullGuide', { path: 'docs/component-authoring.md' }) })] })] })] })] }));
34
+ }) })] }), _jsxs(Card, { className: "flex items-center gap-3 p-4", children: [_jsx("span", { className: "grid size-9 shrink-0 place-items-center rounded-lg bg-muted text-muted-foreground", children: _jsx(MousePointerClick, { className: "size-4" }) }), _jsx(Text, { size: "sm", tone: "muted", children: translate('components.index.pickHint') })] }), _jsxs(Panel, { children: [_jsxs(PanelHeader, { children: [_jsx(Blocks, { className: "size-4 text-muted-foreground" }), _jsx(Text, { size: "sm", weight: "semibold", children: translate('components.index.guide.title') }), _jsx(Spacer, {}), _jsx(Badge, { variant: "outline", children: translate('components.index.guide.badge') })] }), _jsxs(Stack, { gap: "3", className: "p-4", children: [_jsxs(Text, { size: "sm", tone: "muted", children: ["Project code owns its components. Register a manifest under the", ' ', _jsx(Code, { tone: "primary", children: "project.*" }), " namespace (platform primitives live under", ' ', _jsx(Code, { tone: "muted", children: "base.*" }), "). The manifest declares prop schemas, defaults, inspector controls, binding permissions, slots, and preview fixtures."] }), _jsx("pre", { className: "overflow-x-auto rounded-lg border border-border bg-muted/40 p-3 font-mono text-xs leading-relaxed text-foreground/90", children: REGISTER_EXAMPLE }), _jsx(Text, { size: "xs", tone: "subtle", children: translate('components.index.guide.fullGuide', { path: 'docs/component-authoring.md' }) })] })] })] })] }));
35
35
  }
36
36
  function StatCard({ label, value, hint, tone = 'default', }) {
37
37
  const valueClass = tone === 'success'
@@ -1 +1 @@
1
- {"version":3,"file":"components-index.js","sourceRoot":"","sources":["../../../src/components/components/components-index.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Blocks, MousePointerClick } from 'lucide-react'\nimport { getStudioRegistry, registryHealth } from '@elytracms/studio/lib/registry'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { RegistryBrowser } from '@elytracms/studio/components/components/registry-browser'\nimport {\n Badge,\n Card,\n Code,\n Heading,\n Panel,\n PanelHeader,\n Spacer,\n Stack,\n Text,\n} from '@elytracms/studio/ui'\n\nconst REGISTER_EXAMPLE = `// project code registers components + manifests\nimport { defineComponent } from '@elytracms/core/component-registry'\n\nexport const MarketingHeroManifest = defineComponent({\n id: 'project.MarketingHero', // project.* namespace\n namespace: 'project',\n title: 'Marketing Hero',\n props: {\n heading: { schema: z.string().min(1), bindable: true,\n control: { kind: 'text' }, defaultValue: 'Hello' },\n },\n slots: [],\n fixtures: [{ name: 'Default' }],\n})`\n\n/**\n * The Components section landing view (EC-223 Stage 6): registry health overview\n * + the authoring guide, shown when no component is selected. Takes `projectId`\n * as a prop — the splat resolver sources it from the route, not a route file.\n */\nexport function ComponentsIndex({ projectId }: { projectId: string }) {\n const studio = getStudioRegistry()\n const health = registryHealth(studio)\n const primitives = studio.registry.primitives().length\n const projects = studio.registry.projectComponents().length\n\n return (\n <div className=\"mx-auto w-full max-w-4xl p-4 sm:p-6\">\n {/* Mobile-only browser (the sidebar is hidden under md). */}\n <div className=\"mb-6 h-80 overflow-hidden rounded-lg border border-border md:hidden\">\n <RegistryBrowser projectId={projectId} />\n </div>\n\n <Stack gap=\"6\">\n <Stack gap=\"1\">\n <Heading size=\"display\">{translate('components.index.title')}</Heading>\n <Text tone=\"muted\">{translate('components.index.subtitle')}</Text>\n </Stack>\n\n <div className=\"grid gap-3 sm:grid-cols-3\">\n <StatCard\n label={translate('components.index.stat.total')}\n value={health.total}\n hint={translate('components.index.stat.totalHint', { primitives, projects })}\n />\n <StatCard label={translate('components.index.stat.valid')} value={health.valid} tone=\"success\" />\n <StatCard\n label={translate('components.index.stat.needAttention')}\n value={health.incompatible + health.invalid}\n tone={health.incompatible + health.invalid > 0 ? 'warning' : 'muted'}\n hint={translate('components.index.stat.needAttentionHint', {\n incompatible: health.incompatible,\n invalid: health.invalid,\n })}\n />\n </div>\n\n <Card className=\"flex items-center gap-3 p-4\">\n <span className=\"grid size-9 shrink-0 place-items-center rounded-lg bg-muted text-muted-foreground\">\n <MousePointerClick className=\"size-4\" />\n </span>\n <Text size=\"sm\" tone=\"muted\">\n {translate('components.index.pickHint')}\n </Text>\n </Card>\n\n <Panel>\n <PanelHeader>\n <Blocks className=\"size-4 text-muted-foreground\" />\n <Text size=\"sm\" weight=\"semibold\">\n {translate('components.index.guide.title')}\n </Text>\n <Spacer />\n <Badge variant=\"outline\">{translate('components.index.guide.badge')}</Badge>\n </PanelHeader>\n <Stack gap=\"3\" className=\"p-4\">\n <Text size=\"sm\" tone=\"muted\">\n Project code owns its components. Register a manifest under the{' '}\n <Code tone=\"primary\">project.*</Code> namespace (platform primitives live under{' '}\n <Code tone=\"muted\">base.primitives.*</Code>). The manifest declares prop schemas,\n defaults, inspector controls, binding permissions, slots, and preview fixtures.\n </Text>\n <pre className=\"overflow-x-auto rounded-lg border border-border bg-muted/40 p-3 font-mono text-xs leading-relaxed text-foreground/90\">\n {REGISTER_EXAMPLE}\n </pre>\n <Text size=\"xs\" tone=\"subtle\">\n {translate('components.index.guide.fullGuide', { path: 'docs/component-authoring.md' })}\n </Text>\n </Stack>\n </Panel>\n </Stack>\n </div>\n )\n}\n\nfunction StatCard({\n label,\n value,\n hint,\n tone = 'default',\n}: {\n label: string\n value: number\n hint?: string\n tone?: 'default' | 'success' | 'warning' | 'muted'\n}) {\n const valueClass =\n tone === 'success'\n ? 'text-success'\n : tone === 'warning'\n ? 'text-warning'\n : tone === 'muted'\n ? 'text-muted-foreground'\n : 'text-foreground'\n return (\n <Card className=\"p-4\">\n <Text size=\"xs\" tone=\"muted\" mono>\n {label.toUpperCase()}\n </Text>\n <div className={`mt-1 text-2xl font-semibold tracking-tight ${valueClass}`}>{value}</div>\n {hint ? (\n <Text size=\"xs\" tone=\"subtle\" className=\"mt-0.5\">\n {hint}\n </Text>\n ) : null}\n </Card>\n )\n}\n"]}
1
+ {"version":3,"file":"components-index.js","sourceRoot":"","sources":["../../../src/components/components/components-index.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Blocks, MousePointerClick } from 'lucide-react'\nimport { getStudioRegistry, registryHealth } from '@elytracms/studio/lib/registry'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { RegistryBrowser } from '@elytracms/studio/components/components/registry-browser'\nimport {\n Badge,\n Card,\n Code,\n Heading,\n Panel,\n PanelHeader,\n Spacer,\n Stack,\n Text,\n} from '@elytracms/studio/ui'\n\nconst REGISTER_EXAMPLE = `// project code registers components + manifests\nimport { defineComponent } from '@elytracms/core/component-registry'\n\nexport const MarketingHeroManifest = defineComponent({\n id: 'project.MarketingHero', // project.* namespace\n namespace: 'project',\n title: 'Marketing Hero',\n props: {\n heading: { schema: z.string().min(1), bindable: true,\n control: { kind: 'text' }, defaultValue: 'Hello' },\n },\n slots: [],\n fixtures: [{ name: 'Default' }],\n})`\n\n/**\n * The Components section landing view (EC-223 Stage 6): registry health overview\n * + the authoring guide, shown when no component is selected. Takes `projectId`\n * as a prop — the splat resolver sources it from the route, not a route file.\n */\nexport function ComponentsIndex({ projectId }: { projectId: string }) {\n const studio = getStudioRegistry()\n const health = registryHealth(studio)\n const primitives = studio.registry.primitives().length\n const projects = studio.registry.projectComponents().length\n\n return (\n <div className=\"mx-auto w-full max-w-4xl p-4 sm:p-6\">\n {/* Mobile-only browser (the sidebar is hidden under md). */}\n <div className=\"mb-6 h-80 overflow-hidden rounded-lg border border-border md:hidden\">\n <RegistryBrowser projectId={projectId} />\n </div>\n\n <Stack gap=\"6\">\n <Stack gap=\"1\">\n <Heading size=\"display\">{translate('components.index.title')}</Heading>\n <Text tone=\"muted\">{translate('components.index.subtitle')}</Text>\n </Stack>\n\n <div className=\"grid gap-3 sm:grid-cols-3\">\n <StatCard\n label={translate('components.index.stat.total')}\n value={health.total}\n hint={translate('components.index.stat.totalHint', { primitives, projects })}\n />\n <StatCard label={translate('components.index.stat.valid')} value={health.valid} tone=\"success\" />\n <StatCard\n label={translate('components.index.stat.needAttention')}\n value={health.incompatible + health.invalid}\n tone={health.incompatible + health.invalid > 0 ? 'warning' : 'muted'}\n hint={translate('components.index.stat.needAttentionHint', {\n incompatible: health.incompatible,\n invalid: health.invalid,\n })}\n />\n </div>\n\n <Card className=\"flex items-center gap-3 p-4\">\n <span className=\"grid size-9 shrink-0 place-items-center rounded-lg bg-muted text-muted-foreground\">\n <MousePointerClick className=\"size-4\" />\n </span>\n <Text size=\"sm\" tone=\"muted\">\n {translate('components.index.pickHint')}\n </Text>\n </Card>\n\n <Panel>\n <PanelHeader>\n <Blocks className=\"size-4 text-muted-foreground\" />\n <Text size=\"sm\" weight=\"semibold\">\n {translate('components.index.guide.title')}\n </Text>\n <Spacer />\n <Badge variant=\"outline\">{translate('components.index.guide.badge')}</Badge>\n </PanelHeader>\n <Stack gap=\"3\" className=\"p-4\">\n <Text size=\"sm\" tone=\"muted\">\n Project code owns its components. Register a manifest under the{' '}\n <Code tone=\"primary\">project.*</Code> namespace (platform primitives live under{' '}\n <Code tone=\"muted\">base.*</Code>). The manifest declares prop schemas,\n defaults, inspector controls, binding permissions, slots, and preview fixtures.\n </Text>\n <pre className=\"overflow-x-auto rounded-lg border border-border bg-muted/40 p-3 font-mono text-xs leading-relaxed text-foreground/90\">\n {REGISTER_EXAMPLE}\n </pre>\n <Text size=\"xs\" tone=\"subtle\">\n {translate('components.index.guide.fullGuide', { path: 'docs/component-authoring.md' })}\n </Text>\n </Stack>\n </Panel>\n </Stack>\n </div>\n )\n}\n\nfunction StatCard({\n label,\n value,\n hint,\n tone = 'default',\n}: {\n label: string\n value: number\n hint?: string\n tone?: 'default' | 'success' | 'warning' | 'muted'\n}) {\n const valueClass =\n tone === 'success'\n ? 'text-success'\n : tone === 'warning'\n ? 'text-warning'\n : tone === 'muted'\n ? 'text-muted-foreground'\n : 'text-foreground'\n return (\n <Card className=\"p-4\">\n <Text size=\"xs\" tone=\"muted\" mono>\n {label.toUpperCase()}\n </Text>\n <div className={`mt-1 text-2xl font-semibold tracking-tight ${valueClass}`}>{value}</div>\n {hint ? (\n <Text size=\"xs\" tone=\"subtle\" className=\"mt-0.5\">\n {hint}\n </Text>\n ) : null}\n </Card>\n )\n}\n"]}
@@ -36,9 +36,9 @@ export function RegistryBrowser({ projectId, activeComponentId, }) {
36
36
  }), [studio, query, namespace, category]);
37
37
  const primitives = results.filter((m) => isPrimitive(m.id));
38
38
  const projects = results.filter((m) => !isPrimitive(m.id));
39
- return (_jsxs("div", { className: "flex h-full min-h-0 flex-col", children: [_jsxs("div", { className: "shrink-0 space-y-2 border-b border-border p-3", children: [_jsxs("div", { className: "relative", children: [_jsx(Search, { className: "pointer-events-none absolute left-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { value: query, onChange: (e) => setQuery(e.target.value), placeholder: translate('components.browser.searchPlaceholder'), className: "pl-8", "aria-label": translate('components.browser.searchAria') })] }), _jsxs(Row, { gap: "1", className: "rounded-md bg-muted/50 p-0.5", role: "group", "aria-label": translate('components.browser.namespaceAria'), children: [_jsx(NamespaceTab, { label: translate('components.browser.all'), count: primitiveCount + projectCount, active: namespace === 'all', onClick: () => selectNamespace('all') }), _jsx(NamespaceTab, { label: translate('components.browser.primitives'), count: primitiveCount, active: namespace === 'base.primitives', onClick: () => selectNamespace('base.primitives') }), _jsx(NamespaceTab, { label: translate('components.browser.project'), count: projectCount, active: namespace === 'project', onClick: () => selectNamespace('project') })] }), categories.length > 0 ? (_jsxs(Row, { gap: "1", wrap: true, children: [_jsx(CategoryChip, { label: translate('components.browser.all'), active: category === null, onClick: () => setCategory(null) }), categories.map((c) => (_jsx(CategoryChip, { label: c, active: category === c, onClick: () => setCategory(c) }, c)))] })) : null] }), _jsx("div", { className: "min-h-0 flex-1 overflow-auto p-2", children: results.length === 0 ? (_jsx(Text, { size: "sm", tone: "muted", className: "p-3", children: query.trim()
39
+ return (_jsxs("div", { className: "flex h-full min-h-0 flex-col", children: [_jsxs("div", { className: "shrink-0 space-y-2 border-b border-border p-3", children: [_jsxs("div", { className: "relative", children: [_jsx(Search, { className: "pointer-events-none absolute left-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { value: query, onChange: (e) => setQuery(e.target.value), placeholder: translate('components.browser.searchPlaceholder'), className: "pl-8", "aria-label": translate('components.browser.searchAria') })] }), _jsxs(Row, { gap: "1", className: "rounded-md bg-muted/50 p-0.5", role: "group", "aria-label": translate('components.browser.namespaceAria'), children: [_jsx(NamespaceTab, { label: translate('components.browser.all'), count: primitiveCount + projectCount, active: namespace === 'all', onClick: () => selectNamespace('all') }), _jsx(NamespaceTab, { label: translate('components.browser.primitives'), count: primitiveCount, active: namespace === 'base', onClick: () => selectNamespace('base') }), _jsx(NamespaceTab, { label: translate('components.browser.project'), count: projectCount, active: namespace === 'project', onClick: () => selectNamespace('project') })] }), categories.length > 0 ? (_jsxs(Row, { gap: "1", wrap: true, children: [_jsx(CategoryChip, { label: translate('components.browser.all'), active: category === null, onClick: () => setCategory(null) }), categories.map((c) => (_jsx(CategoryChip, { label: c, active: category === c, onClick: () => setCategory(c) }, c)))] })) : null] }), _jsx("div", { className: "min-h-0 flex-1 overflow-auto p-2", children: results.length === 0 ? (_jsx(Text, { size: "sm", tone: "muted", className: "p-3", children: query.trim()
40
40
  ? translate('components.browser.noMatchQuery', { query })
41
- : translate('components.browser.noMatchFilters') })) : (_jsxs(Stack, { gap: "3", children: [(namespace === 'all' || namespace === 'base.primitives') && primitives.length > 0 ? (_jsx(GroupedList, { heading: "base.primitives.*", count: primitives.length, manifests: primitives, projectId: projectId, activeComponentId: activeComponentId })) : null, (namespace === 'all' || namespace === 'project') && projects.length > 0 ? (_jsx(GroupedList, { heading: "project.*", count: projects.length, manifests: projects, projectId: projectId, activeComponentId: activeComponentId })) : null] })) })] }));
41
+ : translate('components.browser.noMatchFilters') })) : (_jsxs(Stack, { gap: "3", children: [(namespace === 'all' || namespace === 'base') && primitives.length > 0 ? (_jsx(GroupedList, { heading: "base.*", count: primitives.length, manifests: primitives, projectId: projectId, activeComponentId: activeComponentId })) : null, (namespace === 'all' || namespace === 'project') && projects.length > 0 ? (_jsx(GroupedList, { heading: "project.*", count: projects.length, manifests: projects, projectId: projectId, activeComponentId: activeComponentId })) : null] })) })] }));
42
42
  }
43
43
  function NamespaceTab({ label, count, active, onClick, }) {
44
44
  return (_jsxs("button", { type: "button", "aria-pressed": active, onClick: onClick, className: cn('flex flex-1 items-center justify-center gap-1.5 rounded-[5px] px-2 py-1 text-xs font-medium transition-colors', active ? 'bg-background text-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground'), children: [label, _jsx("span", { className: "font-mono text-[0.65rem] text-muted-foreground", children: count })] }));
@@ -1 +1 @@
1
- {"version":3,"file":"registry-browser.js","sourceRoot":"","sources":["../../../src/components/components/registry-browser.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Link, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router'\nimport { Search } from 'lucide-react'\nimport { useMemo, useState } from 'react'\nimport { isPrimitive } from '@elytracms/core/component-registry'\nimport type { ComponentManifest } from '@elytracms/core/component-registry'\nimport { componentStatus, getStudioRegistry } from '@elytracms/studio/lib/registry'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { Code, Input, Row, Spacer, Stack, Text } from '@elytracms/studio/ui'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { ComponentStatusDot } from './component-status'\n\ntype NamespaceFilter = 'all' | 'base.primitives' | 'project'\n\nexport function RegistryBrowser({\n projectId,\n activeComponentId,\n}: {\n projectId: string\n activeComponentId?: string\n}) {\n const studio = getStudioRegistry()\n const [query, setQuery] = useState('')\n const [namespace, setNamespace] = useState<NamespaceFilter>('all')\n const [category, setCategory] = useState<string | null>(null)\n\n const primitiveCount = studio.registry.primitives().length\n const projectCount = studio.registry.projectComponents().length\n\n // Switching namespace clears any category that doesn't exist in the new one.\n function selectNamespace(ns: NamespaceFilter) {\n setNamespace(ns)\n setCategory(null)\n }\n\n // Categories are scoped to the active namespace so every chip can yield results.\n const categories = useMemo(() => {\n const set = new Set<string>()\n for (const m of studio.registry.list({ namespace: namespace === 'all' ? undefined : namespace })) {\n if (m.category) set.add(m.category)\n }\n return [...set].sort()\n }, [studio, namespace])\n\n const results = useMemo(\n () =>\n studio.registry.list({\n query: query.trim() || undefined,\n namespace: namespace === 'all' ? undefined : namespace,\n category: category ?? undefined,\n }),\n [studio, query, namespace, category],\n )\n\n const primitives = results.filter((m) => isPrimitive(m.id))\n const projects = results.filter((m) => !isPrimitive(m.id))\n\n return (\n <div className=\"flex h-full min-h-0 flex-col\">\n <div className=\"shrink-0 space-y-2 border-b border-border p-3\">\n <div className=\"relative\">\n <Search className=\"pointer-events-none absolute left-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground\" />\n <Input\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder={translate('components.browser.searchPlaceholder')}\n className=\"pl-8\"\n aria-label={translate('components.browser.searchAria')}\n />\n </div>\n <Row gap=\"1\" className=\"rounded-md bg-muted/50 p-0.5\" role=\"group\" aria-label={translate('components.browser.namespaceAria')}>\n <NamespaceTab label={translate('components.browser.all')} count={primitiveCount + projectCount} active={namespace === 'all'} onClick={() => selectNamespace('all')} />\n <NamespaceTab label={translate('components.browser.primitives')} count={primitiveCount} active={namespace === 'base.primitives'} onClick={() => selectNamespace('base.primitives')} />\n <NamespaceTab label={translate('components.browser.project')} count={projectCount} active={namespace === 'project'} onClick={() => selectNamespace('project')} />\n </Row>\n {categories.length > 0 ? (\n <Row gap=\"1\" wrap>\n <CategoryChip label={translate('components.browser.all')} active={category === null} onClick={() => setCategory(null)} />\n {categories.map((c) => (\n <CategoryChip key={c} label={c} active={category === c} onClick={() => setCategory(c)} />\n ))}\n </Row>\n ) : null}\n </div>\n\n <div className=\"min-h-0 flex-1 overflow-auto p-2\">\n {results.length === 0 ? (\n <Text size=\"sm\" tone=\"muted\" className=\"p-3\">\n {query.trim()\n ? translate('components.browser.noMatchQuery', { query })\n : translate('components.browser.noMatchFilters')}\n </Text>\n ) : (\n <Stack gap=\"3\">\n {(namespace === 'all' || namespace === 'base.primitives') && primitives.length > 0 ? (\n <GroupedList\n heading=\"base.primitives.*\"\n count={primitives.length}\n manifests={primitives}\n projectId={projectId}\n activeComponentId={activeComponentId}\n />\n ) : null}\n {(namespace === 'all' || namespace === 'project') && projects.length > 0 ? (\n <GroupedList\n heading=\"project.*\"\n count={projects.length}\n manifests={projects}\n projectId={projectId}\n activeComponentId={activeComponentId}\n />\n ) : null}\n </Stack>\n )}\n </div>\n </div>\n )\n}\n\nfunction NamespaceTab({\n label,\n count,\n active,\n onClick,\n}: {\n label: string\n count: number\n active: boolean\n onClick: () => void\n}) {\n return (\n <button\n type=\"button\"\n aria-pressed={active}\n onClick={onClick}\n className={cn(\n 'flex flex-1 items-center justify-center gap-1.5 rounded-[5px] px-2 py-1 text-xs font-medium transition-colors',\n active ? 'bg-background text-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground',\n )}\n >\n {label}\n <span className=\"font-mono text-[0.65rem] text-muted-foreground\">{count}</span>\n </button>\n )\n}\n\nfunction CategoryChip({ label, active, onClick }: { label: string; active: boolean; onClick: () => void }) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={cn(\n 'rounded-full border px-2 py-0.5 text-xs capitalize transition-colors',\n active\n ? 'border-primary/30 bg-primary/10 text-primary'\n : 'border-border text-muted-foreground hover:bg-muted',\n )}\n >\n {label}\n </button>\n )\n}\n\nfunction GroupedList({\n heading,\n count,\n manifests,\n projectId,\n activeComponentId,\n}: {\n heading: string\n count: number\n manifests: ComponentManifest[]\n projectId: string\n activeComponentId?: string\n}) {\n const studio = getStudioRegistry()\n return (\n <Stack gap=\"1\">\n <Row gap=\"2\" className=\"px-2\">\n <Code tone=\"muted\">{heading}</Code>\n <Spacer />\n <Text size=\"xs\" tone=\"subtle\" mono>\n {count}\n </Text>\n </Row>\n <Stack gap=\"px\">\n {manifests.map((m) => {\n const status = componentStatus(studio, m)\n const active = m.id === activeComponentId\n return (\n <Link\n key={m.id}\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.component(m.id) }}\n aria-current={active ? 'page' : undefined}\n className={cn(\n 'flex items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors',\n active ? 'bg-accent text-accent-foreground' : 'text-muted-foreground hover:bg-muted hover:text-foreground',\n )}\n >\n <ComponentStatusDot status={status} />\n <span className=\"min-w-0 flex-1 truncate font-medium text-foreground\">{m.title ?? m.id}</span>\n {m.category ? (\n <span className=\"shrink-0 text-[0.7rem] capitalize text-muted-foreground\">{m.category}</span>\n ) : null}\n </Link>\n )\n })}\n </Stack>\n </Stack>\n )\n}\n"]}
1
+ {"version":3,"file":"registry-browser.js","sourceRoot":"","sources":["../../../src/components/components/registry-browser.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Link, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router'\nimport { Search } from 'lucide-react'\nimport { useMemo, useState } from 'react'\nimport { isPrimitive } from '@elytracms/core/component-registry'\nimport type { ComponentManifest } from '@elytracms/core/component-registry'\nimport { componentStatus, getStudioRegistry } from '@elytracms/studio/lib/registry'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { Code, Input, Row, Spacer, Stack, Text } from '@elytracms/studio/ui'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { ComponentStatusDot } from './component-status'\n\ntype NamespaceFilter = 'all' | 'base' | 'project'\n\nexport function RegistryBrowser({\n projectId,\n activeComponentId,\n}: {\n projectId: string\n activeComponentId?: string\n}) {\n const studio = getStudioRegistry()\n const [query, setQuery] = useState('')\n const [namespace, setNamespace] = useState<NamespaceFilter>('all')\n const [category, setCategory] = useState<string | null>(null)\n\n const primitiveCount = studio.registry.primitives().length\n const projectCount = studio.registry.projectComponents().length\n\n // Switching namespace clears any category that doesn't exist in the new one.\n function selectNamespace(ns: NamespaceFilter) {\n setNamespace(ns)\n setCategory(null)\n }\n\n // Categories are scoped to the active namespace so every chip can yield results.\n const categories = useMemo(() => {\n const set = new Set<string>()\n for (const m of studio.registry.list({ namespace: namespace === 'all' ? undefined : namespace })) {\n if (m.category) set.add(m.category)\n }\n return [...set].sort()\n }, [studio, namespace])\n\n const results = useMemo(\n () =>\n studio.registry.list({\n query: query.trim() || undefined,\n namespace: namespace === 'all' ? undefined : namespace,\n category: category ?? undefined,\n }),\n [studio, query, namespace, category],\n )\n\n const primitives = results.filter((m) => isPrimitive(m.id))\n const projects = results.filter((m) => !isPrimitive(m.id))\n\n return (\n <div className=\"flex h-full min-h-0 flex-col\">\n <div className=\"shrink-0 space-y-2 border-b border-border p-3\">\n <div className=\"relative\">\n <Search className=\"pointer-events-none absolute left-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground\" />\n <Input\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder={translate('components.browser.searchPlaceholder')}\n className=\"pl-8\"\n aria-label={translate('components.browser.searchAria')}\n />\n </div>\n <Row gap=\"1\" className=\"rounded-md bg-muted/50 p-0.5\" role=\"group\" aria-label={translate('components.browser.namespaceAria')}>\n <NamespaceTab label={translate('components.browser.all')} count={primitiveCount + projectCount} active={namespace === 'all'} onClick={() => selectNamespace('all')} />\n <NamespaceTab label={translate('components.browser.primitives')} count={primitiveCount} active={namespace === 'base'} onClick={() => selectNamespace('base')} />\n <NamespaceTab label={translate('components.browser.project')} count={projectCount} active={namespace === 'project'} onClick={() => selectNamespace('project')} />\n </Row>\n {categories.length > 0 ? (\n <Row gap=\"1\" wrap>\n <CategoryChip label={translate('components.browser.all')} active={category === null} onClick={() => setCategory(null)} />\n {categories.map((c) => (\n <CategoryChip key={c} label={c} active={category === c} onClick={() => setCategory(c)} />\n ))}\n </Row>\n ) : null}\n </div>\n\n <div className=\"min-h-0 flex-1 overflow-auto p-2\">\n {results.length === 0 ? (\n <Text size=\"sm\" tone=\"muted\" className=\"p-3\">\n {query.trim()\n ? translate('components.browser.noMatchQuery', { query })\n : translate('components.browser.noMatchFilters')}\n </Text>\n ) : (\n <Stack gap=\"3\">\n {(namespace === 'all' || namespace === 'base') && primitives.length > 0 ? (\n <GroupedList\n heading=\"base.*\"\n count={primitives.length}\n manifests={primitives}\n projectId={projectId}\n activeComponentId={activeComponentId}\n />\n ) : null}\n {(namespace === 'all' || namespace === 'project') && projects.length > 0 ? (\n <GroupedList\n heading=\"project.*\"\n count={projects.length}\n manifests={projects}\n projectId={projectId}\n activeComponentId={activeComponentId}\n />\n ) : null}\n </Stack>\n )}\n </div>\n </div>\n )\n}\n\nfunction NamespaceTab({\n label,\n count,\n active,\n onClick,\n}: {\n label: string\n count: number\n active: boolean\n onClick: () => void\n}) {\n return (\n <button\n type=\"button\"\n aria-pressed={active}\n onClick={onClick}\n className={cn(\n 'flex flex-1 items-center justify-center gap-1.5 rounded-[5px] px-2 py-1 text-xs font-medium transition-colors',\n active ? 'bg-background text-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground',\n )}\n >\n {label}\n <span className=\"font-mono text-[0.65rem] text-muted-foreground\">{count}</span>\n </button>\n )\n}\n\nfunction CategoryChip({ label, active, onClick }: { label: string; active: boolean; onClick: () => void }) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={cn(\n 'rounded-full border px-2 py-0.5 text-xs capitalize transition-colors',\n active\n ? 'border-primary/30 bg-primary/10 text-primary'\n : 'border-border text-muted-foreground hover:bg-muted',\n )}\n >\n {label}\n </button>\n )\n}\n\nfunction GroupedList({\n heading,\n count,\n manifests,\n projectId,\n activeComponentId,\n}: {\n heading: string\n count: number\n manifests: ComponentManifest[]\n projectId: string\n activeComponentId?: string\n}) {\n const studio = getStudioRegistry()\n return (\n <Stack gap=\"1\">\n <Row gap=\"2\" className=\"px-2\">\n <Code tone=\"muted\">{heading}</Code>\n <Spacer />\n <Text size=\"xs\" tone=\"subtle\" mono>\n {count}\n </Text>\n </Row>\n <Stack gap=\"px\">\n {manifests.map((m) => {\n const status = componentStatus(studio, m)\n const active = m.id === activeComponentId\n return (\n <Link\n key={m.id}\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.component(m.id) }}\n aria-current={active ? 'page' : undefined}\n className={cn(\n 'flex items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors',\n active ? 'bg-accent text-accent-foreground' : 'text-muted-foreground hover:bg-muted hover:text-foreground',\n )}\n >\n <ComponentStatusDot status={status} />\n <span className=\"min-w-0 flex-1 truncate font-medium text-foreground\">{m.title ?? m.id}</span>\n {m.category ? (\n <span className=\"shrink-0 text-[0.7rem] capitalize text-muted-foreground\">{m.category}</span>\n ) : null}\n </Link>\n )\n })}\n </Stack>\n </Stack>\n )\n}\n"]}
@@ -64,7 +64,7 @@ function ContributionChip({ icon, label, count }) {
64
64
  // --- Registered (inspect) ---------------------------------------------------
65
65
  function RegisteredTab({ host }) {
66
66
  const hookPoints = host.hooks.points();
67
- return (_jsxs(Stack, { gap: "6", children: [_jsx(Text, { size: "xs", tone: "subtle", children: translate('extensions.registered.intro') }), _jsx(InspectGroup, { icon: _jsx(Boxes, {}), title: translate('extensions.registered.components.title'), sub: "base.primitives.* + project + vendor packages", children: _jsx(ChipRow, { items: host.components.projectComponents().map((m) => m.id), empty: translate('extensions.registered.components.empty') }) }), _jsx(InspectGroup, { icon: _jsx(Type, {}), title: translate('extensions.registered.fieldTypes.title'), children: _jsx(ChipRow, { items: [...BUILTIN_FIELD_TYPES], tone: "builtin", suffix: host.fieldTypes.list().map((f) => f.kind) }) }), _jsx(InspectGroup, { icon: _jsx(Database, {}), title: translate('extensions.registered.dataSources.title'), children: _jsx(ChipRow, { items: [...BUILTIN_SOURCE_KINDS], tone: "builtin", suffix: host.dataSources.list().map((a) => a.kind) }) }), _jsx(InspectGroup, { icon: _jsx(HardDrive, {}), title: translate('extensions.registered.assetStorage.title'), children: _jsx(ChipRow, { items: host.assetStorage.list().map((a) => `${a.kind} · ${a.title}`), empty: translate('extensions.registered.assetStorage.empty') }) }), _jsx(InspectGroup, { icon: _jsx(Share2, {}), title: translate('extensions.registered.exportTargets.title'), children: _jsx(ChipRow, { items: ['next-app-router · reference'], tone: "builtin", suffix: host.exportTargets.list().map((t) => `${t.id} · ${t.title}`) }) }), _jsx(InspectGroup, { icon: _jsx(Webhook, {}), title: translate('extensions.registered.hookPoints.title'), children: _jsx(ChipRow, { items: [...HOOK_POINTS], tone: "builtin", suffix: hookPoints.flatMap((p) => host.hooks.list(p).map((t) => `${p}${t.plugin ? ` ← ${t.plugin}` : ''}`)) }) })] }));
67
+ return (_jsxs(Stack, { gap: "6", children: [_jsx(Text, { size: "xs", tone: "subtle", children: translate('extensions.registered.intro') }), _jsx(InspectGroup, { icon: _jsx(Boxes, {}), title: translate('extensions.registered.components.title'), sub: "base.* + project + vendor packages", children: _jsx(ChipRow, { items: host.components.projectComponents().map((m) => m.id), empty: translate('extensions.registered.components.empty') }) }), _jsx(InspectGroup, { icon: _jsx(Type, {}), title: translate('extensions.registered.fieldTypes.title'), children: _jsx(ChipRow, { items: [...BUILTIN_FIELD_TYPES], tone: "builtin", suffix: host.fieldTypes.list().map((f) => f.kind) }) }), _jsx(InspectGroup, { icon: _jsx(Database, {}), title: translate('extensions.registered.dataSources.title'), children: _jsx(ChipRow, { items: [...BUILTIN_SOURCE_KINDS], tone: "builtin", suffix: host.dataSources.list().map((a) => a.kind) }) }), _jsx(InspectGroup, { icon: _jsx(HardDrive, {}), title: translate('extensions.registered.assetStorage.title'), children: _jsx(ChipRow, { items: host.assetStorage.list().map((a) => `${a.kind} · ${a.title}`), empty: translate('extensions.registered.assetStorage.empty') }) }), _jsx(InspectGroup, { icon: _jsx(Share2, {}), title: translate('extensions.registered.exportTargets.title'), children: _jsx(ChipRow, { items: ['next-app-router · reference'], tone: "builtin", suffix: host.exportTargets.list().map((t) => `${t.id} · ${t.title}`) }) }), _jsx(InspectGroup, { icon: _jsx(Webhook, {}), title: translate('extensions.registered.hookPoints.title'), children: _jsx(ChipRow, { items: [...HOOK_POINTS], tone: "builtin", suffix: hookPoints.flatMap((p) => host.hooks.list(p).map((t) => `${p}${t.plugin ? ` ← ${t.plugin}` : ''}`)) }) })] }));
68
68
  }
69
69
  function InspectGroup({ icon, title, sub, children, }) {
70
70
  return (_jsxs(Stack, { gap: "2", children: [_jsxs(Row, { gap: "2", children: [_jsx("span", { className: "grid size-5 place-items-center text-primary [&_svg]:size-4", children: icon }), _jsx(Text, { size: "sm", weight: "semibold", children: title }), sub ? (_jsx(Text, { size: "xs", tone: "subtle", children: sub })) : null] }), children] }));
@@ -1 +1 @@
1
- {"version":3,"file":"extensions-view.js","sourceRoot":"","sources":["../../../src/components/extensions/extensions-view.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo, useReducer, useState } from 'react'\nimport {\n Boxes,\n Check,\n Database,\n Download,\n HardDrive,\n Lock,\n Package,\n Puzzle,\n Search,\n Share2,\n LayoutTemplate,\n Type,\n Webhook,\n} from 'lucide-react'\nimport {\n BUILTIN_FIELD_TYPES,\n BUILTIN_SOURCE_KINDS,\n HOOK_POINTS,\n MarketplaceClient,\n PluginHost,\n privateMarketplace,\n publicMarketplace,\n} from '@elytracms/core/plugins'\nimport type { ExtensionKind, ExtensionListing, InstalledPlugin, MarketplaceInstallResult } from '@elytracms/core/plugins'\nimport { Badge, Button, Code, Heading, Input, Row, Spacer, Stack, Text } from '@elytracms/studio/ui'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { cn } from '@elytracms/studio/lib/utils'\n\ntype Tab = 'marketplace' | 'installed' | 'registered'\n\n/**\n * The Extensions surface (Phase 11, EC-130–137). A live, agent-inspectable view over the\n * extensibility layer: browse a public + private marketplace, install plugins into a host, and\n * inspect what each surface contributes (components, field types, data sources, asset storage,\n * export targets, hooks). All state is deterministic — driven by `@elytracms/core/plugins` fixtures.\n */\nexport function ExtensionsView() {\n // One host for the session; PluginHost mutates in place, so a bump reducer drives re-render.\n const [host] = useState(() => new PluginHost())\n const [, bump] = useReducer((n: number) => n + 1, 0)\n const [tab, setTab] = useState<Tab>('marketplace')\n const [token, setToken] = useState('')\n const [query, setQuery] = useState('')\n const [results, setResults] = useState<Record<string, MarketplaceInstallResult>>({})\n\n const client = useMemo(\n () => new MarketplaceClient([publicMarketplace, privateMarketplace], token.trim() ? { 'acme-private': token.trim() } : {}),\n [token],\n )\n\n const hits = client.search(query.trim() ? { query: query.trim() } : {})\n const privateUnlocked = client.accessibleRegistries().some((r) => r.id === 'acme-private')\n const installedCount = host.list().length\n\n function install(listing: ExtensionListing) {\n const result = client.install(host, listing.id)\n setResults((prev) => ({ ...prev, [listing.id]: result }))\n bump()\n }\n\n return (\n <div className=\"flex h-full min-h-0 flex-col\">\n <ExtensionsHeader\n tab={tab}\n onTab={setTab}\n installedCount={installedCount}\n marketCount={hits.length}\n />\n\n <div className=\"min-h-0 flex-1 overflow-auto px-4 py-5 sm:px-6\">\n <div className=\"mx-auto w-full max-w-5xl\">\n {tab === 'marketplace' ? (\n <MarketplaceTab\n hits={hits}\n query={query}\n onQuery={setQuery}\n token={token}\n onToken={setToken}\n privateUnlocked={privateUnlocked}\n isInstalled={(l) => host.isInstalled(l.plugin.id)}\n onInstall={install}\n results={results}\n />\n ) : tab === 'installed' ? (\n <InstalledTab installed={host.list()} />\n ) : (\n <RegisteredTab host={host} />\n )}\n </div>\n </div>\n </div>\n )\n}\n\n// --- Header + tabs ----------------------------------------------------------\n\nfunction ExtensionsHeader({\n tab,\n onTab,\n installedCount,\n marketCount,\n}: {\n tab: Tab\n onTab: (t: Tab) => void\n installedCount: number\n marketCount: number\n}) {\n const tabs: { id: Tab; label: string; count?: number }[] = [\n { id: 'marketplace', label: translate('extensions.tab.marketplace'), count: marketCount },\n { id: 'installed', label: translate('extensions.tab.installed'), count: installedCount },\n { id: 'registered', label: translate('extensions.tab.registered') },\n ]\n return (\n <div className=\"shrink-0 border-b border-border bg-gradient-to-b from-primary/[0.04] to-transparent px-4 py-3 sm:px-6\">\n <Row gap=\"3\">\n <span className=\"grid size-8 shrink-0 place-items-center rounded-lg bg-primary/15 text-primary\">\n <Puzzle className=\"size-4\" />\n </span>\n <Stack gap=\"none\" className=\"min-w-0\">\n <Text size=\"sm\" weight=\"semibold\">\n {translate('extensions.header.title')}\n </Text>\n <Text size=\"xs\" tone=\"subtle\">\n {translate('extensions.header.subtitle')}\n </Text>\n </Stack>\n <Spacer />\n <Row gap=\"1\" className=\"rounded-md bg-muted/50 p-0.5\">\n {tabs.map((t) => (\n <button\n key={t.id}\n type=\"button\"\n aria-pressed={tab === t.id}\n onClick={() => onTab(t.id)}\n className={cn(\n 'flex items-center gap-1.5 rounded-[5px] px-3 py-1 text-sm font-medium transition-colors',\n tab === t.id ? 'bg-background text-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground',\n )}\n >\n {t.label}\n {t.count !== undefined ? (\n <span className=\"rounded-full bg-muted px-1.5 text-[0.7rem] font-semibold tabular-nums text-muted-foreground\">\n {t.count}\n </span>\n ) : null}\n </button>\n ))}\n </Row>\n </Row>\n </div>\n )\n}\n\n// --- Marketplace ------------------------------------------------------------\n\nfunction MarketplaceTab({\n hits,\n query,\n onQuery,\n token,\n onToken,\n privateUnlocked,\n isInstalled,\n onInstall,\n results,\n}: {\n hits: { registryId: string; listing: ExtensionListing }[]\n query: string\n onQuery: (q: string) => void\n token: string\n onToken: (t: string) => void\n privateUnlocked: boolean\n isInstalled: (l: ExtensionListing) => boolean\n onInstall: (l: ExtensionListing) => void\n results: Record<string, MarketplaceInstallResult>\n}) {\n return (\n <Stack gap=\"6\">\n <Row gap=\"3\" wrap>\n <div className=\"relative min-w-0 flex-1\">\n <Search className=\"pointer-events-none absolute left-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground\" />\n <Input\n value={query}\n onChange={(e) => onQuery(e.target.value)}\n placeholder={translate('extensions.search.placeholder')}\n className=\"pl-8\"\n aria-label={translate('extensions.search.aria')}\n />\n </div>\n <Row gap=\"2\" className=\"shrink-0\">\n <Lock className={cn('size-3.5', privateUnlocked ? 'text-success' : 'text-muted-foreground')} />\n <Input\n value={token}\n onChange={(e) => onToken(e.target.value)}\n placeholder={translate('extensions.token.placeholder')}\n aria-label={translate('extensions.token.placeholder')}\n className=\"w-52\"\n />\n {privateUnlocked ? <Badge variant=\"success\">{translate('extensions.token.unlocked')}</Badge> : null}\n </Row>\n </Row>\n\n {!privateUnlocked ? (\n <Text size=\"xs\" tone=\"subtle\">\n A private registry is available. Enter its access token (hint: <Code tone=\"muted\">acme-internal-token</Code>) to\n reveal private listings.\n </Text>\n ) : null}\n\n {hits.length === 0 ? (\n <EmptyHint\n icon={<Search className=\"size-5\" />}\n title={translate('extensions.empty.noMatch.title')}\n body={translate('extensions.empty.noMatch.body')}\n />\n ) : (\n <div className=\"grid gap-3 sm:grid-cols-2\">\n {hits.map(({ registryId, listing }) => (\n <ListingCard\n key={listing.id}\n listing={listing}\n registryId={registryId}\n installed={isInstalled(listing)}\n result={results[listing.id]}\n onInstall={() => onInstall(listing)}\n />\n ))}\n </div>\n )}\n </Stack>\n )\n}\n\nfunction ListingCard({\n listing,\n registryId,\n installed,\n result,\n onInstall,\n}: {\n listing: ExtensionListing\n registryId: string\n installed: boolean\n result: MarketplaceInstallResult | undefined\n onInstall: () => void\n}) {\n const failed = result && !result.ok\n return (\n <div className=\"flex flex-col rounded-xl border border-border bg-card/60 p-4 transition-colors hover:border-primary/40\">\n <Row gap=\"2\">\n <span className=\"grid size-9 shrink-0 place-items-center rounded-lg bg-muted text-foreground/80\">\n <KindIcon kind={listing.kind} />\n </span>\n <Stack gap=\"none\" className=\"min-w-0\">\n <Text size=\"sm\" weight=\"semibold\" className=\"truncate\">\n {listing.name}\n </Text>\n <Row gap=\"1\" className=\"text-muted-foreground\">\n <KindBadge kind={listing.kind} />\n <Code tone=\"muted\">v{listing.version}</Code>\n </Row>\n </Stack>\n <Spacer />\n {registryId === 'acme-private' ? (\n <Badge variant=\"outline\">\n <Lock className=\"size-3\" /> private\n </Badge>\n ) : null}\n </Row>\n\n <Text size=\"xs\" tone=\"muted\" className=\"mt-3 line-clamp-3 min-h-0 flex-1\">\n {listing.description ?? translate('extensions.listing.noDescription')}\n </Text>\n\n {listing.tags && listing.tags.length > 0 ? (\n <Row gap=\"1\" wrap className=\"mt-3\">\n {listing.tags.map((tag) => (\n <span key={tag} className=\"rounded-full bg-muted/70 px-2 py-0.5 text-[0.7rem] text-muted-foreground\">\n {tag}\n </span>\n ))}\n </Row>\n ) : null}\n\n <Row gap=\"2\" className=\"mt-4\">\n <Text size=\"xs\" tone=\"subtle\" className=\"truncate\">\n {listing.author ?? translate('extensions.listing.unknownAuthor')}\n </Text>\n <Spacer />\n {installed ? (\n <Button size=\"sm\" variant=\"ghost\" disabled>\n <Check /> {translate('extensions.action.installed')}\n </Button>\n ) : (\n <Button size=\"sm\" variant={failed ? 'destructive' : 'default'} onClick={onInstall}>\n <Download /> {failed ? translate('common.retry') : translate('extensions.action.install')}\n </Button>\n )}\n </Row>\n\n {failed ? (\n <Text size=\"xs\" className=\"mt-2 text-destructive\">\n {result?.blocked === 'access-denied'\n ? translate('extensions.error.accessDenied')\n : result?.issues[0]?.message ?? translate('extensions.error.installFailed')}\n </Text>\n ) : null}\n </div>\n )\n}\n\n// --- Installed --------------------------------------------------------------\n\nfunction InstalledTab({ installed }: { installed: InstalledPlugin[] }) {\n if (installed.length === 0) {\n return (\n <EmptyHint\n icon={<Boxes className=\"size-5\" />}\n title={translate('extensions.empty.installed.title')}\n body={translate('extensions.empty.installed.body')}\n />\n )\n }\n return (\n <Stack gap=\"3\">\n {installed.map((plugin) => (\n <div key={plugin.id} className=\"rounded-xl border border-border bg-card/60 p-4\">\n <Row gap=\"2\">\n <Package className=\"size-4 text-primary\" />\n <Text size=\"sm\" weight=\"semibold\">\n {plugin.name}\n </Text>\n <Code tone=\"muted\">v{plugin.version}</Code>\n <Spacer />\n <Text size=\"xs\" tone=\"subtle\">\n {plugin.author ?? ''}\n </Text>\n </Row>\n {plugin.description ? (\n <Text size=\"xs\" tone=\"muted\" className=\"mt-2\">\n {plugin.description}\n </Text>\n ) : null}\n <Row gap=\"2\" wrap className=\"mt-3\">\n <ContributionChip icon={<Boxes />} label={translate('extensions.contrib.components')} count={plugin.contributes.components} />\n <ContributionChip icon={<Type />} label={translate('extensions.contrib.fieldTypes')} count={plugin.contributes.fieldTypes} />\n <ContributionChip icon={<Database />} label={translate('extensions.contrib.dataSources')} count={plugin.contributes.dataSources} />\n <ContributionChip icon={<HardDrive />} label={translate('extensions.contrib.assetStorage')} count={plugin.contributes.assetStorage} />\n <ContributionChip icon={<Share2 />} label={translate('extensions.contrib.exportTargets')} count={plugin.contributes.exportTargets} />\n <ContributionChip icon={<LayoutTemplate />} label={translate('extensions.contrib.templates')} count={plugin.contributes.templates} />\n <ContributionChip icon={<Webhook />} label={translate('extensions.contrib.hooks')} count={plugin.contributes.hooks} />\n </Row>\n </div>\n ))}\n </Stack>\n )\n}\n\nfunction ContributionChip({ icon, label, count }: { icon: React.ReactNode; label: string; count: number }) {\n if (count === 0) return null\n return (\n <span className=\"inline-flex items-center gap-1.5 rounded-md border border-border/60 bg-muted/40 px-2 py-1 text-xs text-muted-foreground\">\n <span className=\"grid size-3.5 place-items-center text-primary [&_svg]:size-3.5\">{icon}</span>\n <span className=\"font-semibold tabular-nums text-foreground\">{count}</span>\n {label}\n </span>\n )\n}\n\n// --- Registered (inspect) ---------------------------------------------------\n\nfunction RegisteredTab({ host }: { host: PluginHost }) {\n const hookPoints = host.hooks.points()\n return (\n <Stack gap=\"6\">\n <Text size=\"xs\" tone=\"subtle\">\n {translate('extensions.registered.intro')}\n </Text>\n\n <InspectGroup icon={<Boxes />} title={translate('extensions.registered.components.title')} sub=\"base.primitives.* + project + vendor packages\">\n <ChipRow items={host.components.projectComponents().map((m) => m.id)} empty={translate('extensions.registered.components.empty')} />\n </InspectGroup>\n\n <InspectGroup icon={<Type />} title={translate('extensions.registered.fieldTypes.title')}>\n <ChipRow\n items={[...BUILTIN_FIELD_TYPES]}\n tone=\"builtin\"\n suffix={host.fieldTypes.list().map((f) => f.kind)}\n />\n </InspectGroup>\n\n <InspectGroup icon={<Database />} title={translate('extensions.registered.dataSources.title')}>\n <ChipRow items={[...BUILTIN_SOURCE_KINDS]} tone=\"builtin\" suffix={host.dataSources.list().map((a) => a.kind)} />\n </InspectGroup>\n\n <InspectGroup icon={<HardDrive />} title={translate('extensions.registered.assetStorage.title')}>\n <ChipRow items={host.assetStorage.list().map((a) => `${a.kind} · ${a.title}`)} empty={translate('extensions.registered.assetStorage.empty')} />\n </InspectGroup>\n\n <InspectGroup icon={<Share2 />} title={translate('extensions.registered.exportTargets.title')}>\n <ChipRow\n items={['next-app-router · reference']}\n tone=\"builtin\"\n suffix={host.exportTargets.list().map((t) => `${t.id} · ${t.title}`)}\n />\n </InspectGroup>\n\n <InspectGroup icon={<Webhook />} title={translate('extensions.registered.hookPoints.title')}>\n <ChipRow\n items={[...HOOK_POINTS]}\n tone=\"builtin\"\n suffix={hookPoints.flatMap((p) => host.hooks.list(p).map((t) => `${p}${t.plugin ? ` ← ${t.plugin}` : ''}`))}\n />\n </InspectGroup>\n </Stack>\n )\n}\n\nfunction InspectGroup({\n icon,\n title,\n sub,\n children,\n}: {\n icon: React.ReactNode\n title: string\n sub?: string\n children: React.ReactNode\n}) {\n return (\n <Stack gap=\"2\">\n <Row gap=\"2\">\n <span className=\"grid size-5 place-items-center text-primary [&_svg]:size-4\">{icon}</span>\n <Text size=\"sm\" weight=\"semibold\">\n {title}\n </Text>\n {sub ? (\n <Text size=\"xs\" tone=\"subtle\">\n {sub}\n </Text>\n ) : null}\n </Row>\n {children}\n </Stack>\n )\n}\n\nfunction ChipRow({\n items,\n suffix,\n tone,\n empty,\n}: {\n items: string[]\n suffix?: string[]\n tone?: 'builtin'\n empty?: string\n}) {\n const all = [...items.map((v) => ({ v, builtin: tone === 'builtin' })), ...(suffix ?? []).map((v) => ({ v, builtin: false }))]\n if (all.length === 0) {\n return (\n <Text size=\"xs\" tone=\"subtle\">\n {empty ?? translate('common.none')}\n </Text>\n )\n }\n return (\n <Row gap=\"1\" wrap>\n {all.map(({ v, builtin }) => (\n <span\n key={v}\n className={cn(\n 'rounded-md border px-2 py-0.5 font-mono text-xs',\n builtin\n ? 'border-border/60 bg-muted/40 text-muted-foreground'\n : 'border-primary/30 bg-primary/10 text-primary',\n )}\n >\n {v}\n </span>\n ))}\n </Row>\n )\n}\n\n// --- Shared bits -------------------------------------------------------------\n\nfunction EmptyHint({ icon, title, body }: { icon: React.ReactNode; title: string; body: string }) {\n return (\n <Stack gap=\"2\" align=\"center\" className=\"rounded-xl border border-dashed border-border/70 px-6 py-16 text-center\">\n <span className=\"grid size-10 place-items-center rounded-full bg-muted text-muted-foreground\">{icon}</span>\n <Heading level={3} size=\"h4\">\n {title}\n </Heading>\n <Text size=\"sm\" tone=\"muted\" className=\"max-w-sm\">\n {body}\n </Text>\n </Stack>\n )\n}\n\nconst KIND_LABEL_KEY: Record<ExtensionKind, string> = {\n plugin: 'extensions.kind.plugin',\n 'component-package': 'extensions.kind.componentPackage',\n 'field-type': 'extensions.kind.fieldType',\n 'data-source': 'extensions.kind.dataSource',\n 'asset-storage': 'extensions.kind.assetStorage',\n 'export-target': 'extensions.kind.exportTarget',\n template: 'extensions.kind.template',\n}\n\nfunction KindBadge({ kind }: { kind: ExtensionKind }) {\n const variant =\n kind === 'plugin'\n ? 'primary'\n : kind === 'field-type'\n ? 'success'\n : kind === 'data-source'\n ? 'warning'\n : kind === 'template'\n ? 'info'\n : 'outline'\n return <Badge variant={variant}>{translate(KIND_LABEL_KEY[kind])}</Badge>\n}\n\nfunction KindIcon({ kind }: { kind: ExtensionKind }) {\n const className = 'size-4'\n switch (kind) {\n case 'plugin':\n return <Puzzle className={className} />\n case 'component-package':\n return <Boxes className={className} />\n case 'field-type':\n return <Type className={className} />\n case 'data-source':\n return <Database className={className} />\n case 'asset-storage':\n return <HardDrive className={className} />\n case 'export-target':\n return <Share2 className={className} />\n case 'template':\n return <LayoutTemplate className={className} />\n default:\n return <Package className={className} />\n }\n}\n"]}
1
+ {"version":3,"file":"extensions-view.js","sourceRoot":"","sources":["../../../src/components/extensions/extensions-view.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo, useReducer, useState } from 'react'\nimport {\n Boxes,\n Check,\n Database,\n Download,\n HardDrive,\n Lock,\n Package,\n Puzzle,\n Search,\n Share2,\n LayoutTemplate,\n Type,\n Webhook,\n} from 'lucide-react'\nimport {\n BUILTIN_FIELD_TYPES,\n BUILTIN_SOURCE_KINDS,\n HOOK_POINTS,\n MarketplaceClient,\n PluginHost,\n privateMarketplace,\n publicMarketplace,\n} from '@elytracms/core/plugins'\nimport type { ExtensionKind, ExtensionListing, InstalledPlugin, MarketplaceInstallResult } from '@elytracms/core/plugins'\nimport { Badge, Button, Code, Heading, Input, Row, Spacer, Stack, Text } from '@elytracms/studio/ui'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { cn } from '@elytracms/studio/lib/utils'\n\ntype Tab = 'marketplace' | 'installed' | 'registered'\n\n/**\n * The Extensions surface (Phase 11, EC-130–137). A live, agent-inspectable view over the\n * extensibility layer: browse a public + private marketplace, install plugins into a host, and\n * inspect what each surface contributes (components, field types, data sources, asset storage,\n * export targets, hooks). All state is deterministic — driven by `@elytracms/core/plugins` fixtures.\n */\nexport function ExtensionsView() {\n // One host for the session; PluginHost mutates in place, so a bump reducer drives re-render.\n const [host] = useState(() => new PluginHost())\n const [, bump] = useReducer((n: number) => n + 1, 0)\n const [tab, setTab] = useState<Tab>('marketplace')\n const [token, setToken] = useState('')\n const [query, setQuery] = useState('')\n const [results, setResults] = useState<Record<string, MarketplaceInstallResult>>({})\n\n const client = useMemo(\n () => new MarketplaceClient([publicMarketplace, privateMarketplace], token.trim() ? { 'acme-private': token.trim() } : {}),\n [token],\n )\n\n const hits = client.search(query.trim() ? { query: query.trim() } : {})\n const privateUnlocked = client.accessibleRegistries().some((r) => r.id === 'acme-private')\n const installedCount = host.list().length\n\n function install(listing: ExtensionListing) {\n const result = client.install(host, listing.id)\n setResults((prev) => ({ ...prev, [listing.id]: result }))\n bump()\n }\n\n return (\n <div className=\"flex h-full min-h-0 flex-col\">\n <ExtensionsHeader\n tab={tab}\n onTab={setTab}\n installedCount={installedCount}\n marketCount={hits.length}\n />\n\n <div className=\"min-h-0 flex-1 overflow-auto px-4 py-5 sm:px-6\">\n <div className=\"mx-auto w-full max-w-5xl\">\n {tab === 'marketplace' ? (\n <MarketplaceTab\n hits={hits}\n query={query}\n onQuery={setQuery}\n token={token}\n onToken={setToken}\n privateUnlocked={privateUnlocked}\n isInstalled={(l) => host.isInstalled(l.plugin.id)}\n onInstall={install}\n results={results}\n />\n ) : tab === 'installed' ? (\n <InstalledTab installed={host.list()} />\n ) : (\n <RegisteredTab host={host} />\n )}\n </div>\n </div>\n </div>\n )\n}\n\n// --- Header + tabs ----------------------------------------------------------\n\nfunction ExtensionsHeader({\n tab,\n onTab,\n installedCount,\n marketCount,\n}: {\n tab: Tab\n onTab: (t: Tab) => void\n installedCount: number\n marketCount: number\n}) {\n const tabs: { id: Tab; label: string; count?: number }[] = [\n { id: 'marketplace', label: translate('extensions.tab.marketplace'), count: marketCount },\n { id: 'installed', label: translate('extensions.tab.installed'), count: installedCount },\n { id: 'registered', label: translate('extensions.tab.registered') },\n ]\n return (\n <div className=\"shrink-0 border-b border-border bg-gradient-to-b from-primary/[0.04] to-transparent px-4 py-3 sm:px-6\">\n <Row gap=\"3\">\n <span className=\"grid size-8 shrink-0 place-items-center rounded-lg bg-primary/15 text-primary\">\n <Puzzle className=\"size-4\" />\n </span>\n <Stack gap=\"none\" className=\"min-w-0\">\n <Text size=\"sm\" weight=\"semibold\">\n {translate('extensions.header.title')}\n </Text>\n <Text size=\"xs\" tone=\"subtle\">\n {translate('extensions.header.subtitle')}\n </Text>\n </Stack>\n <Spacer />\n <Row gap=\"1\" className=\"rounded-md bg-muted/50 p-0.5\">\n {tabs.map((t) => (\n <button\n key={t.id}\n type=\"button\"\n aria-pressed={tab === t.id}\n onClick={() => onTab(t.id)}\n className={cn(\n 'flex items-center gap-1.5 rounded-[5px] px-3 py-1 text-sm font-medium transition-colors',\n tab === t.id ? 'bg-background text-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground',\n )}\n >\n {t.label}\n {t.count !== undefined ? (\n <span className=\"rounded-full bg-muted px-1.5 text-[0.7rem] font-semibold tabular-nums text-muted-foreground\">\n {t.count}\n </span>\n ) : null}\n </button>\n ))}\n </Row>\n </Row>\n </div>\n )\n}\n\n// --- Marketplace ------------------------------------------------------------\n\nfunction MarketplaceTab({\n hits,\n query,\n onQuery,\n token,\n onToken,\n privateUnlocked,\n isInstalled,\n onInstall,\n results,\n}: {\n hits: { registryId: string; listing: ExtensionListing }[]\n query: string\n onQuery: (q: string) => void\n token: string\n onToken: (t: string) => void\n privateUnlocked: boolean\n isInstalled: (l: ExtensionListing) => boolean\n onInstall: (l: ExtensionListing) => void\n results: Record<string, MarketplaceInstallResult>\n}) {\n return (\n <Stack gap=\"6\">\n <Row gap=\"3\" wrap>\n <div className=\"relative min-w-0 flex-1\">\n <Search className=\"pointer-events-none absolute left-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground\" />\n <Input\n value={query}\n onChange={(e) => onQuery(e.target.value)}\n placeholder={translate('extensions.search.placeholder')}\n className=\"pl-8\"\n aria-label={translate('extensions.search.aria')}\n />\n </div>\n <Row gap=\"2\" className=\"shrink-0\">\n <Lock className={cn('size-3.5', privateUnlocked ? 'text-success' : 'text-muted-foreground')} />\n <Input\n value={token}\n onChange={(e) => onToken(e.target.value)}\n placeholder={translate('extensions.token.placeholder')}\n aria-label={translate('extensions.token.placeholder')}\n className=\"w-52\"\n />\n {privateUnlocked ? <Badge variant=\"success\">{translate('extensions.token.unlocked')}</Badge> : null}\n </Row>\n </Row>\n\n {!privateUnlocked ? (\n <Text size=\"xs\" tone=\"subtle\">\n A private registry is available. Enter its access token (hint: <Code tone=\"muted\">acme-internal-token</Code>) to\n reveal private listings.\n </Text>\n ) : null}\n\n {hits.length === 0 ? (\n <EmptyHint\n icon={<Search className=\"size-5\" />}\n title={translate('extensions.empty.noMatch.title')}\n body={translate('extensions.empty.noMatch.body')}\n />\n ) : (\n <div className=\"grid gap-3 sm:grid-cols-2\">\n {hits.map(({ registryId, listing }) => (\n <ListingCard\n key={listing.id}\n listing={listing}\n registryId={registryId}\n installed={isInstalled(listing)}\n result={results[listing.id]}\n onInstall={() => onInstall(listing)}\n />\n ))}\n </div>\n )}\n </Stack>\n )\n}\n\nfunction ListingCard({\n listing,\n registryId,\n installed,\n result,\n onInstall,\n}: {\n listing: ExtensionListing\n registryId: string\n installed: boolean\n result: MarketplaceInstallResult | undefined\n onInstall: () => void\n}) {\n const failed = result && !result.ok\n return (\n <div className=\"flex flex-col rounded-xl border border-border bg-card/60 p-4 transition-colors hover:border-primary/40\">\n <Row gap=\"2\">\n <span className=\"grid size-9 shrink-0 place-items-center rounded-lg bg-muted text-foreground/80\">\n <KindIcon kind={listing.kind} />\n </span>\n <Stack gap=\"none\" className=\"min-w-0\">\n <Text size=\"sm\" weight=\"semibold\" className=\"truncate\">\n {listing.name}\n </Text>\n <Row gap=\"1\" className=\"text-muted-foreground\">\n <KindBadge kind={listing.kind} />\n <Code tone=\"muted\">v{listing.version}</Code>\n </Row>\n </Stack>\n <Spacer />\n {registryId === 'acme-private' ? (\n <Badge variant=\"outline\">\n <Lock className=\"size-3\" /> private\n </Badge>\n ) : null}\n </Row>\n\n <Text size=\"xs\" tone=\"muted\" className=\"mt-3 line-clamp-3 min-h-0 flex-1\">\n {listing.description ?? translate('extensions.listing.noDescription')}\n </Text>\n\n {listing.tags && listing.tags.length > 0 ? (\n <Row gap=\"1\" wrap className=\"mt-3\">\n {listing.tags.map((tag) => (\n <span key={tag} className=\"rounded-full bg-muted/70 px-2 py-0.5 text-[0.7rem] text-muted-foreground\">\n {tag}\n </span>\n ))}\n </Row>\n ) : null}\n\n <Row gap=\"2\" className=\"mt-4\">\n <Text size=\"xs\" tone=\"subtle\" className=\"truncate\">\n {listing.author ?? translate('extensions.listing.unknownAuthor')}\n </Text>\n <Spacer />\n {installed ? (\n <Button size=\"sm\" variant=\"ghost\" disabled>\n <Check /> {translate('extensions.action.installed')}\n </Button>\n ) : (\n <Button size=\"sm\" variant={failed ? 'destructive' : 'default'} onClick={onInstall}>\n <Download /> {failed ? translate('common.retry') : translate('extensions.action.install')}\n </Button>\n )}\n </Row>\n\n {failed ? (\n <Text size=\"xs\" className=\"mt-2 text-destructive\">\n {result?.blocked === 'access-denied'\n ? translate('extensions.error.accessDenied')\n : result?.issues[0]?.message ?? translate('extensions.error.installFailed')}\n </Text>\n ) : null}\n </div>\n )\n}\n\n// --- Installed --------------------------------------------------------------\n\nfunction InstalledTab({ installed }: { installed: InstalledPlugin[] }) {\n if (installed.length === 0) {\n return (\n <EmptyHint\n icon={<Boxes className=\"size-5\" />}\n title={translate('extensions.empty.installed.title')}\n body={translate('extensions.empty.installed.body')}\n />\n )\n }\n return (\n <Stack gap=\"3\">\n {installed.map((plugin) => (\n <div key={plugin.id} className=\"rounded-xl border border-border bg-card/60 p-4\">\n <Row gap=\"2\">\n <Package className=\"size-4 text-primary\" />\n <Text size=\"sm\" weight=\"semibold\">\n {plugin.name}\n </Text>\n <Code tone=\"muted\">v{plugin.version}</Code>\n <Spacer />\n <Text size=\"xs\" tone=\"subtle\">\n {plugin.author ?? ''}\n </Text>\n </Row>\n {plugin.description ? (\n <Text size=\"xs\" tone=\"muted\" className=\"mt-2\">\n {plugin.description}\n </Text>\n ) : null}\n <Row gap=\"2\" wrap className=\"mt-3\">\n <ContributionChip icon={<Boxes />} label={translate('extensions.contrib.components')} count={plugin.contributes.components} />\n <ContributionChip icon={<Type />} label={translate('extensions.contrib.fieldTypes')} count={plugin.contributes.fieldTypes} />\n <ContributionChip icon={<Database />} label={translate('extensions.contrib.dataSources')} count={plugin.contributes.dataSources} />\n <ContributionChip icon={<HardDrive />} label={translate('extensions.contrib.assetStorage')} count={plugin.contributes.assetStorage} />\n <ContributionChip icon={<Share2 />} label={translate('extensions.contrib.exportTargets')} count={plugin.contributes.exportTargets} />\n <ContributionChip icon={<LayoutTemplate />} label={translate('extensions.contrib.templates')} count={plugin.contributes.templates} />\n <ContributionChip icon={<Webhook />} label={translate('extensions.contrib.hooks')} count={plugin.contributes.hooks} />\n </Row>\n </div>\n ))}\n </Stack>\n )\n}\n\nfunction ContributionChip({ icon, label, count }: { icon: React.ReactNode; label: string; count: number }) {\n if (count === 0) return null\n return (\n <span className=\"inline-flex items-center gap-1.5 rounded-md border border-border/60 bg-muted/40 px-2 py-1 text-xs text-muted-foreground\">\n <span className=\"grid size-3.5 place-items-center text-primary [&_svg]:size-3.5\">{icon}</span>\n <span className=\"font-semibold tabular-nums text-foreground\">{count}</span>\n {label}\n </span>\n )\n}\n\n// --- Registered (inspect) ---------------------------------------------------\n\nfunction RegisteredTab({ host }: { host: PluginHost }) {\n const hookPoints = host.hooks.points()\n return (\n <Stack gap=\"6\">\n <Text size=\"xs\" tone=\"subtle\">\n {translate('extensions.registered.intro')}\n </Text>\n\n <InspectGroup icon={<Boxes />} title={translate('extensions.registered.components.title')} sub=\"base.* + project + vendor packages\">\n <ChipRow items={host.components.projectComponents().map((m) => m.id)} empty={translate('extensions.registered.components.empty')} />\n </InspectGroup>\n\n <InspectGroup icon={<Type />} title={translate('extensions.registered.fieldTypes.title')}>\n <ChipRow\n items={[...BUILTIN_FIELD_TYPES]}\n tone=\"builtin\"\n suffix={host.fieldTypes.list().map((f) => f.kind)}\n />\n </InspectGroup>\n\n <InspectGroup icon={<Database />} title={translate('extensions.registered.dataSources.title')}>\n <ChipRow items={[...BUILTIN_SOURCE_KINDS]} tone=\"builtin\" suffix={host.dataSources.list().map((a) => a.kind)} />\n </InspectGroup>\n\n <InspectGroup icon={<HardDrive />} title={translate('extensions.registered.assetStorage.title')}>\n <ChipRow items={host.assetStorage.list().map((a) => `${a.kind} · ${a.title}`)} empty={translate('extensions.registered.assetStorage.empty')} />\n </InspectGroup>\n\n <InspectGroup icon={<Share2 />} title={translate('extensions.registered.exportTargets.title')}>\n <ChipRow\n items={['next-app-router · reference']}\n tone=\"builtin\"\n suffix={host.exportTargets.list().map((t) => `${t.id} · ${t.title}`)}\n />\n </InspectGroup>\n\n <InspectGroup icon={<Webhook />} title={translate('extensions.registered.hookPoints.title')}>\n <ChipRow\n items={[...HOOK_POINTS]}\n tone=\"builtin\"\n suffix={hookPoints.flatMap((p) => host.hooks.list(p).map((t) => `${p}${t.plugin ? ` ← ${t.plugin}` : ''}`))}\n />\n </InspectGroup>\n </Stack>\n )\n}\n\nfunction InspectGroup({\n icon,\n title,\n sub,\n children,\n}: {\n icon: React.ReactNode\n title: string\n sub?: string\n children: React.ReactNode\n}) {\n return (\n <Stack gap=\"2\">\n <Row gap=\"2\">\n <span className=\"grid size-5 place-items-center text-primary [&_svg]:size-4\">{icon}</span>\n <Text size=\"sm\" weight=\"semibold\">\n {title}\n </Text>\n {sub ? (\n <Text size=\"xs\" tone=\"subtle\">\n {sub}\n </Text>\n ) : null}\n </Row>\n {children}\n </Stack>\n )\n}\n\nfunction ChipRow({\n items,\n suffix,\n tone,\n empty,\n}: {\n items: string[]\n suffix?: string[]\n tone?: 'builtin'\n empty?: string\n}) {\n const all = [...items.map((v) => ({ v, builtin: tone === 'builtin' })), ...(suffix ?? []).map((v) => ({ v, builtin: false }))]\n if (all.length === 0) {\n return (\n <Text size=\"xs\" tone=\"subtle\">\n {empty ?? translate('common.none')}\n </Text>\n )\n }\n return (\n <Row gap=\"1\" wrap>\n {all.map(({ v, builtin }) => (\n <span\n key={v}\n className={cn(\n 'rounded-md border px-2 py-0.5 font-mono text-xs',\n builtin\n ? 'border-border/60 bg-muted/40 text-muted-foreground'\n : 'border-primary/30 bg-primary/10 text-primary',\n )}\n >\n {v}\n </span>\n ))}\n </Row>\n )\n}\n\n// --- Shared bits -------------------------------------------------------------\n\nfunction EmptyHint({ icon, title, body }: { icon: React.ReactNode; title: string; body: string }) {\n return (\n <Stack gap=\"2\" align=\"center\" className=\"rounded-xl border border-dashed border-border/70 px-6 py-16 text-center\">\n <span className=\"grid size-10 place-items-center rounded-full bg-muted text-muted-foreground\">{icon}</span>\n <Heading level={3} size=\"h4\">\n {title}\n </Heading>\n <Text size=\"sm\" tone=\"muted\" className=\"max-w-sm\">\n {body}\n </Text>\n </Stack>\n )\n}\n\nconst KIND_LABEL_KEY: Record<ExtensionKind, string> = {\n plugin: 'extensions.kind.plugin',\n 'component-package': 'extensions.kind.componentPackage',\n 'field-type': 'extensions.kind.fieldType',\n 'data-source': 'extensions.kind.dataSource',\n 'asset-storage': 'extensions.kind.assetStorage',\n 'export-target': 'extensions.kind.exportTarget',\n template: 'extensions.kind.template',\n}\n\nfunction KindBadge({ kind }: { kind: ExtensionKind }) {\n const variant =\n kind === 'plugin'\n ? 'primary'\n : kind === 'field-type'\n ? 'success'\n : kind === 'data-source'\n ? 'warning'\n : kind === 'template'\n ? 'info'\n : 'outline'\n return <Badge variant={variant}>{translate(KIND_LABEL_KEY[kind])}</Badge>\n}\n\nfunction KindIcon({ kind }: { kind: ExtensionKind }) {\n const className = 'size-4'\n switch (kind) {\n case 'plugin':\n return <Puzzle className={className} />\n case 'component-package':\n return <Boxes className={className} />\n case 'field-type':\n return <Type className={className} />\n case 'data-source':\n return <Database className={className} />\n case 'asset-storage':\n return <HardDrive className={className} />\n case 'export-target':\n return <Share2 className={className} />\n case 'template':\n return <LayoutTemplate className={className} />\n default:\n return <Package className={className} />\n }\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { getNode, getParentInfo } from '@elytracms/core/project-graph';
2
2
  function shortId(componentId) {
3
- return componentId.replace('base.primitives.', '').replace('project.', '');
3
+ return componentId.replace('base.', '').replace('project.', '');
4
4
  }
5
5
  export function resolvePasteTarget(args) {
6
6
  const { root, getManifest } = args;
@@ -1 +1 @@
1
- {"version":3,"file":"paste-target.js","sourceRoot":"","sources":["../../../src/lib/clipboard/paste-target.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AAkBtE,SAAS,OAAO,CAAC,WAAmB;IAClC,OAAO,WAAW,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;AAC5E,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAKlC;IACC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,IAAI,CAAA;IAClC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAChF,MAAM,IAAI,GAAG,MAAM,IAAI,IAAI,CAAA;IAE3B,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;IAC9C,MAAM,SAAS,GACb,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC;QAClD,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAA;IAClD,IAAI,SAAS,EAAE,CAAC;QACd,OAAO;YACL,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE;YACnD,gBAAgB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,SAAS,CAAC,IAAI,EAAE;SACrE,CAAA;IACH,CAAC;IAED,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAA;IACzC,IAAI,IAAI,EAAE,CAAC;QACT,OAAO;YACL,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,EAAE;YAC5E,gBAAgB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE;SACvE,CAAA;IACH,CAAC;IAED,8EAA8E;IAC9E,OAAO,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAA;AACtF,CAAC","sourcesContent":["import { getNode, getParentInfo } from '@elytracms/core/project-graph'\nimport type { ComponentNode, InsertTarget } from '@elytracms/core/project-graph'\nimport type { ComponentManifest } from '@elytracms/core/component-registry'\n\n/**\n * Paste landing-spot resolution (EC-175) — the same placement rule the Insert\n * dialog uses (`insert-context.ts`): a pasted subtree lands *into*\n * the anchor node's child slot when it has one, else *after* the anchor as a\n * sibling, else appended to the page root. Pure and selection-driven so the\n * canvas, the page tree, and keyboard paste all share one rule.\n */\n\nexport interface PasteTarget {\n target: InsertTarget\n /** Human label of where the paste lands (notices/debugging). */\n destinationLabel: string\n}\n\nfunction shortId(componentId: string): string {\n return componentId.replace('base.primitives.', '').replace('project.', '')\n}\n\nexport function resolvePasteTarget(args: {\n root: ComponentNode\n /** The anchor node (usually the selection); `null` falls back to the root. */\n anchorId: string | null\n getManifest: (componentId: string) => ComponentManifest | undefined\n}): PasteTarget {\n const { root, getManifest } = args\n const anchor = args.anchorId !== null ? getNode(root, args.anchorId) : undefined\n const node = anchor ?? root\n\n const manifest = getManifest(node.componentId)\n const childSlot =\n manifest?.slots.find((s) => s.name === 'children') ??\n manifest?.slots.find((s) => s.name !== 'outlet')\n if (childSlot) {\n return {\n target: { parentId: node.id, slot: childSlot.name },\n destinationLabel: `${shortId(node.componentId)} · ${childSlot.name}`,\n }\n }\n\n const info = getParentInfo(root, node.id)\n if (info) {\n return {\n target: { parentId: info.parent.id, slot: info.slot, index: info.index + 1 },\n destinationLabel: `${shortId(info.parent.componentId)} · ${info.slot}`,\n }\n }\n\n // Leaf root with no declared slots (degenerate graphs): append to `children`.\n return { target: { parentId: root.id, slot: 'children' }, destinationLabel: 'root' }\n}\n"]}
1
+ {"version":3,"file":"paste-target.js","sourceRoot":"","sources":["../../../src/lib/clipboard/paste-target.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AAkBtE,SAAS,OAAO,CAAC,WAAmB;IAClC,OAAO,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;AACjE,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAKlC;IACC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,IAAI,CAAA;IAClC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAChF,MAAM,IAAI,GAAG,MAAM,IAAI,IAAI,CAAA;IAE3B,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;IAC9C,MAAM,SAAS,GACb,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC;QAClD,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAA;IAClD,IAAI,SAAS,EAAE,CAAC;QACd,OAAO;YACL,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE;YACnD,gBAAgB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,SAAS,CAAC,IAAI,EAAE;SACrE,CAAA;IACH,CAAC;IAED,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAA;IACzC,IAAI,IAAI,EAAE,CAAC;QACT,OAAO;YACL,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,EAAE;YAC5E,gBAAgB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE;SACvE,CAAA;IACH,CAAC;IAED,8EAA8E;IAC9E,OAAO,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAA;AACtF,CAAC","sourcesContent":["import { getNode, getParentInfo } from '@elytracms/core/project-graph'\nimport type { ComponentNode, InsertTarget } from '@elytracms/core/project-graph'\nimport type { ComponentManifest } from '@elytracms/core/component-registry'\n\n/**\n * Paste landing-spot resolution (EC-175) — the same placement rule the Insert\n * dialog uses (`insert-context.ts`): a pasted subtree lands *into*\n * the anchor node's child slot when it has one, else *after* the anchor as a\n * sibling, else appended to the page root. Pure and selection-driven so the\n * canvas, the page tree, and keyboard paste all share one rule.\n */\n\nexport interface PasteTarget {\n target: InsertTarget\n /** Human label of where the paste lands (notices/debugging). */\n destinationLabel: string\n}\n\nfunction shortId(componentId: string): string {\n return componentId.replace('base.', '').replace('project.', '')\n}\n\nexport function resolvePasteTarget(args: {\n root: ComponentNode\n /** The anchor node (usually the selection); `null` falls back to the root. */\n anchorId: string | null\n getManifest: (componentId: string) => ComponentManifest | undefined\n}): PasteTarget {\n const { root, getManifest } = args\n const anchor = args.anchorId !== null ? getNode(root, args.anchorId) : undefined\n const node = anchor ?? root\n\n const manifest = getManifest(node.componentId)\n const childSlot =\n manifest?.slots.find((s) => s.name === 'children') ??\n manifest?.slots.find((s) => s.name !== 'outlet')\n if (childSlot) {\n return {\n target: { parentId: node.id, slot: childSlot.name },\n destinationLabel: `${shortId(node.componentId)} · ${childSlot.name}`,\n }\n }\n\n const info = getParentInfo(root, node.id)\n if (info) {\n return {\n target: { parentId: info.parent.id, slot: info.slot, index: info.index + 1 },\n destinationLabel: `${shortId(info.parent.componentId)} · ${info.slot}`,\n }\n }\n\n // Leaf root with no declared slots (degenerate graphs): append to `children`.\n return { target: { parentId: root.id, slot: 'children' }, destinationLabel: 'root' }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { DEFAULT_SLOT, GRID_COMPONENT_ID, OUTLET_SLOT, STACK_COMPONENT_ID, getNode, getParentInfo, gridContainerNode, isDescendantOf, removeNode, updateNode, } from '@elytracms/core/project-graph';
1
+ import { DEFAULT_SLOT, GRID_COMPONENT_ID, OUTLET_SLOT, STACK_COMPONENT_ID, getNode, getParentInfo, gridContainerNode, isDescendantOf, isStaticProp, removeNode, updateNode, } from '@elytracms/core/project-graph';
2
2
  function rejected(code, reason) {
3
3
  return { eligible: false, code, reason };
4
4
  }
@@ -182,7 +182,7 @@ export function applyWrap(args) {
182
182
  }
183
183
  function staticPropValue(node, name) {
184
184
  const prop = node.props?.[name];
185
- return prop?.kind === 'static' ? prop.value : undefined;
185
+ return isStaticProp(prop) ? prop.value : undefined;
186
186
  }
187
187
  /**
188
188
  * The flow axis of a container — the axis its children stack along, and