@elytracms/studio 0.0.63 → 0.0.65

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 (146) hide show
  1. package/convex/assets.ts +11 -0
  2. package/convex/delivery.ts +5 -0
  3. package/convex/schema.ts +23 -0
  4. package/dist/components/assets/asset-thumb.d.ts +4 -2
  5. package/dist/components/assets/asset-thumb.js +26 -4
  6. package/dist/components/assets/asset-thumb.js.map +1 -1
  7. package/dist/components/assets/assets-module.js +48 -2
  8. package/dist/components/assets/assets-module.js.map +1 -1
  9. package/dist/components/assets/assets-store.d.ts +11 -1
  10. package/dist/components/assets/assets-store.js +18 -1
  11. package/dist/components/assets/assets-store.js.map +1 -1
  12. package/dist/components/builder/blocks-model.d.ts +11 -0
  13. package/dist/components/builder/blocks-model.js +26 -8
  14. package/dist/components/builder/blocks-model.js.map +1 -1
  15. package/dist/components/builder/canvas-chrome-css.d.ts +54 -0
  16. package/dist/components/builder/canvas-chrome-css.js +246 -0
  17. package/dist/components/builder/canvas-chrome-css.js.map +1 -0
  18. package/dist/components/builder/canvas-chrome.d.ts +122 -18
  19. package/dist/components/builder/canvas-chrome.js +148 -82
  20. package/dist/components/builder/canvas-chrome.js.map +1 -1
  21. package/dist/components/builder/canvas-inline-editing.d.ts +7 -0
  22. package/dist/components/builder/canvas-inline-editing.js +3 -1
  23. package/dist/components/builder/canvas-inline-editing.js.map +1 -1
  24. package/dist/components/builder/canvas-overlay-geometry.d.ts +72 -0
  25. package/dist/components/builder/canvas-overlay-geometry.js +80 -0
  26. package/dist/components/builder/canvas-overlay-geometry.js.map +1 -0
  27. package/dist/components/builder/canvas-rect-tracking.d.ts +124 -0
  28. package/dist/components/builder/canvas-rect-tracking.js +198 -0
  29. package/dist/components/builder/canvas-rect-tracking.js.map +1 -0
  30. package/dist/components/builder/canvas-render-context.d.ts +13 -0
  31. package/dist/components/builder/canvas-render-context.js +7 -5
  32. package/dist/components/builder/canvas-render-context.js.map +1 -1
  33. package/dist/components/builder/canvas-stylesheet.d.ts +1 -1
  34. package/dist/components/builder/canvas-stylesheet.js +16 -9
  35. package/dist/components/builder/canvas-stylesheet.js.map +1 -1
  36. package/dist/components/builder/canvas-theme-notice.d.ts +6 -0
  37. package/dist/components/builder/canvas-theme-notice.js +46 -0
  38. package/dist/components/builder/canvas-theme-notice.js.map +1 -0
  39. package/dist/components/builder/canvas.js +78 -22
  40. package/dist/components/builder/canvas.js.map +1 -1
  41. package/dist/components/builder/composition-field-editor.js +22 -3
  42. package/dist/components/builder/composition-field-editor.js.map +1 -1
  43. package/dist/components/builder/delete-key.d.ts +38 -0
  44. package/dist/components/builder/delete-key.js +46 -0
  45. package/dist/components/builder/delete-key.js.map +1 -0
  46. package/dist/components/builder/drag-session.d.ts +8 -0
  47. package/dist/components/builder/drag-session.js +15 -0
  48. package/dist/components/builder/drag-session.js.map +1 -1
  49. package/dist/components/builder/insert-affordance-context.d.ts +19 -0
  50. package/dist/components/builder/insert-affordance-context.js +7 -0
  51. package/dist/components/builder/insert-affordance-context.js.map +1 -0
  52. package/dist/components/builder/insert-context.d.ts +40 -0
  53. package/dist/components/builder/insert-context.js +86 -3
  54. package/dist/components/builder/insert-context.js.map +1 -1
  55. package/dist/components/builder/node-title.d.ts +60 -0
  56. package/dist/components/builder/node-title.js +135 -0
  57. package/dist/components/builder/node-title.js.map +1 -0
  58. package/dist/components/builder/page-tree.js +21 -3
  59. package/dist/components/builder/page-tree.js.map +1 -1
  60. package/dist/components/builder/prop-selection.d.ts +52 -0
  61. package/dist/components/builder/prop-selection.js +38 -0
  62. package/dist/components/builder/prop-selection.js.map +1 -0
  63. package/dist/components/builder/prop-sync-context.d.ts +49 -0
  64. package/dist/components/builder/prop-sync-context.js +23 -0
  65. package/dist/components/builder/prop-sync-context.js.map +1 -0
  66. package/dist/components/builder/property-inspector.js +23 -1
  67. package/dist/components/builder/property-inspector.js.map +1 -1
  68. package/dist/components/builder/reuse-context.js +1 -1
  69. package/dist/components/builder/reuse-context.js.map +1 -1
  70. package/dist/components/builder/rich-text-toolbar.d.ts +23 -0
  71. package/dist/components/builder/rich-text-toolbar.js +24 -17
  72. package/dist/components/builder/rich-text-toolbar.js.map +1 -1
  73. package/dist/components/builder/selection-overlay.d.ts +79 -0
  74. package/dist/components/builder/selection-overlay.js +244 -0
  75. package/dist/components/builder/selection-overlay.js.map +1 -0
  76. package/dist/components/builder/spacing-handles.d.ts +88 -1
  77. package/dist/components/builder/spacing-handles.js +191 -63
  78. package/dist/components/builder/spacing-handles.js.map +1 -1
  79. package/dist/components/cms/asset-picker.js +11 -5
  80. package/dist/components/cms/asset-picker.js.map +1 -1
  81. package/dist/components/cms/rich-text/block-style.d.ts +48 -0
  82. package/dist/components/cms/rich-text/block-style.js +30 -0
  83. package/dist/components/cms/rich-text/block-style.js.map +1 -0
  84. package/dist/components/cms/rich-text/embed-picker.js +4 -3
  85. package/dist/components/cms/rich-text/embed-picker.js.map +1 -1
  86. package/dist/components/cms/rich-text/extensions.d.ts +2 -0
  87. package/dist/components/cms/rich-text/extensions.js +4 -0
  88. package/dist/components/cms/rich-text/extensions.js.map +1 -1
  89. package/dist/components/cms/rich-text/font-size-control.d.ts +31 -0
  90. package/dist/components/cms/rich-text/font-size-control.js +40 -0
  91. package/dist/components/cms/rich-text/font-size-control.js.map +1 -0
  92. package/dist/components/cms/rich-text/font-size.d.ts +16 -0
  93. package/dist/components/cms/rich-text/font-size.js +40 -0
  94. package/dist/components/cms/rich-text/font-size.js.map +1 -0
  95. package/dist/components/cms/rich-text/toolbar-state.d.ts +3 -0
  96. package/dist/components/cms/rich-text/toolbar-state.js +3 -0
  97. package/dist/components/cms/rich-text/toolbar-state.js.map +1 -1
  98. package/dist/components/cms/rich-text/toolbar.d.ts +13 -0
  99. package/dist/components/cms/rich-text/toolbar.js +17 -5
  100. package/dist/components/cms/rich-text/toolbar.js.map +1 -1
  101. package/dist/components/components/component-detail.js +3 -3
  102. package/dist/components/components/component-detail.js.map +1 -1
  103. package/dist/components/components/component-preview.d.ts +2 -1
  104. package/dist/components/components/component-preview.js +25 -26
  105. package/dist/components/components/component-preview.js.map +1 -1
  106. package/dist/components/components/registry-browser.js +2 -2
  107. package/dist/components/components/registry-browser.js.map +1 -1
  108. package/dist/components/components/taxonomy.js +3 -2
  109. package/dist/components/components/taxonomy.js.map +1 -1
  110. package/dist/components/components/transfer-dialog.js +1 -1
  111. package/dist/components/components/transfer-dialog.js.map +1 -1
  112. package/dist/lib/assets/backfill-thumbs.d.ts +67 -0
  113. package/dist/lib/assets/backfill-thumbs.js +120 -0
  114. package/dist/lib/assets/backfill-thumbs.js.map +1 -0
  115. package/dist/lib/assets/delete-asset.d.ts +2 -1
  116. package/dist/lib/assets/delete-asset.js +12 -0
  117. package/dist/lib/assets/delete-asset.js.map +1 -1
  118. package/dist/lib/assets/index.d.ts +2 -0
  119. package/dist/lib/assets/index.js +2 -0
  120. package/dist/lib/assets/index.js.map +1 -1
  121. package/dist/lib/assets/thumbnail.d.ts +145 -0
  122. package/dist/lib/assets/thumbnail.js +220 -0
  123. package/dist/lib/assets/thumbnail.js.map +1 -0
  124. package/dist/lib/assets/upload.d.ts +9 -0
  125. package/dist/lib/assets/upload.js +31 -0
  126. package/dist/lib/assets/upload.js.map +1 -1
  127. package/dist/lib/i18n/messages.de.js +20 -0
  128. package/dist/lib/i18n/messages.de.js.map +1 -1
  129. package/dist/lib/i18n/messages.en.d.ts +18 -0
  130. package/dist/lib/i18n/messages.en.js +21 -0
  131. package/dist/lib/i18n/messages.en.js.map +1 -1
  132. package/dist/lib/persistence/backend-mode.d.ts +7 -0
  133. package/dist/lib/persistence/backend-mode.js +9 -0
  134. package/dist/lib/persistence/backend-mode.js.map +1 -1
  135. package/dist/lib/persistence/convex-adapter.js +4 -0
  136. package/dist/lib/persistence/convex-adapter.js.map +1 -1
  137. package/dist/lib/persistence/index.d.ts +1 -1
  138. package/dist/lib/persistence/index.js +1 -1
  139. package/dist/lib/persistence/index.js.map +1 -1
  140. package/dist/lib/persona/labels.d.ts +9 -5
  141. package/dist/lib/persona/labels.js +13 -8
  142. package/dist/lib/persona/labels.js.map +1 -1
  143. package/dist/lib/references/references-store.js +7 -1
  144. package/dist/lib/references/references-store.js.map +1 -1
  145. package/package.json +2 -2
  146. package/src/styles/studio.css +13 -0
@@ -1,12 +1,14 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useEditorState } from '@tiptap/react';
3
- import { Blocks, Bold, ChevronDown, Code, ImagePlus, Italic, Maximize2, Minimize2, Pilcrow, Redo2, Strikethrough, Underline, Undo2, } from 'lucide-react';
3
+ import { Blocks, Bold, ChevronDown, Code, ImagePlus, Italic, Maximize2, Minimize2, Redo2, Strikethrough, Underline, Undo2, } from 'lucide-react';
4
4
  import { Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, Toolbar, ToolbarGroup, ToolbarSeparator, } from '@elytracms/studio/ui';
5
5
  import { translate } from '@elytracms/studio/lib/i18n';
6
6
  import { ToolbarButton } from './toolbar-button.js';
7
7
  import { LinkControl } from './link-control.js';
8
8
  import { toolbarStateFromEditor } from './toolbar-state.js';
9
9
  import { BLOCK_COMMANDS, isBlockCommandActive } from './block-commands.js';
10
+ import { BLOCK_STYLES, BlockStyleGlyph, blockStyleLabel } from './block-style.js';
11
+ import { FontSizeControl } from './font-size-control.js';
10
12
  /**
11
13
  * The toolbar container classes (EC-391). The load-bearing part is the height
12
14
  * contract: `h-auto min-h-10` (NOT a fixed `h-10`/`h-11`) so that when the many
@@ -18,6 +20,19 @@ import { BLOCK_COMMANDS, isBlockCommandActive } from './block-commands.js';
18
20
  * Pinned by `toolbar-layout.test.ts`.
19
21
  */
20
22
  export const RICH_TEXT_TOOLBAR_CLASS = 'h-auto min-h-10 flex-wrap gap-0.5 rounded-none border-x-0 border-t-0 bg-muted/30 px-1.5 py-1';
23
+ /**
24
+ * The block-style dropdown trigger's class (EC-418). The load-bearing part is the
25
+ * FIXED width (`w-12`): the trigger shows the active style's icon glyph (not its
26
+ * variable-width localized label — "Absatz" ≪ "Überschrift 2"), so caret movement
27
+ * across Absatz/H1/H2/H3 can never change the trigger's width and reflow the wrapped
28
+ * strip beneath the cursor (the reported German-locale defect). `justify-between`
29
+ * seats the glyph and the ChevronDown in that fixed box. Every other control on the
30
+ * strip is already a fixed `size-7` square (`ToolbarButton`, `LinkControl`) whose
31
+ * active state only recolors (a `secondary` border sits inside the box-border square,
32
+ * never resizing it) — so this trigger was the sole selection-variable width.
33
+ * Pinned by `toolbar-layout.test.ts`.
34
+ */
35
+ export const RICH_TEXT_MENU_TRIGGER_CLASS = 'h-7 w-12 justify-between gap-1 px-2';
21
36
  /**
22
37
  * The CMS rich-text toolbar (EC-314) — a compact, Notion-grade control strip that
23
38
  * reads its active/enabled state reactively from the editor (`useEditorState`) so a
@@ -34,9 +49,6 @@ export function RichTextToolbar({ editor, targets, onOpenImage, onOpenEmbed, exp
34
49
  editor,
35
50
  selector: ({ editor }) => toolbarStateFromEditor(editor),
36
51
  });
37
- const styleLabel = state.headingLevel != null
38
- ? translate('richText.heading', { level: state.headingLevel })
39
- : translate('richText.paragraph');
40
- return (_jsxs(Toolbar, { className: RICH_TEXT_TOOLBAR_CLASS, children: [_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: "h-7 gap-1 px-2 font-medium", onMouseDown: (e) => e.preventDefault(), children: [styleLabel, _jsx(ChevronDown, { className: "size-3 opacity-60" })] }) }), _jsxs(DropdownMenuContent, { align: "start", className: "min-w-40", children: [_jsxs(DropdownMenuItem, { onSelect: () => editor.chain().focus().setParagraph().run(), children: [_jsx(Pilcrow, { className: "size-3.5" }), " ", translate('richText.paragraph')] }), [1, 2, 3].map((level) => (_jsxs(DropdownMenuItem, { onSelect: () => editor.chain().focus().toggleHeading({ level }).run(), children: [_jsxs("span", { className: "w-3.5 text-center text-xs font-semibold", children: ["H", level] }), ' ', translate('richText.heading', { level })] }, level)))] })] }), _jsx(ToolbarSeparator, {}), _jsxs(ToolbarGroup, { children: [_jsx(ToolbarButton, { active: state.bold, label: translate('richText.bold'), onClick: () => editor.chain().focus().toggleBold().run(), children: _jsx(Bold, { className: "size-3.5" }) }), _jsx(ToolbarButton, { active: state.italic, label: translate('richText.italic'), onClick: () => editor.chain().focus().toggleItalic().run(), children: _jsx(Italic, { className: "size-3.5" }) }), _jsx(ToolbarButton, { active: state.underline, label: translate('richText.underline'), onClick: () => editor.chain().focus().toggleUnderline().run(), children: _jsx(Underline, { className: "size-3.5" }) }), _jsx(ToolbarButton, { active: state.strike, label: translate('richText.strike'), onClick: () => editor.chain().focus().toggleStrike().run(), children: _jsx(Strikethrough, { className: "size-3.5" }) }), _jsx(ToolbarButton, { active: state.code, label: translate('richText.code'), onClick: () => editor.chain().focus().toggleCode().run(), children: _jsx(Code, { className: "size-3.5" }) })] }), _jsx(ToolbarSeparator, {}), _jsx(ToolbarGroup, { children: BLOCK_COMMANDS.map((cmd) => (_jsx(ToolbarButton, { active: isBlockCommandActive(cmd, state), label: translate(cmd.labelKey), onClick: () => cmd.chain(editor.chain().focus()).run(), children: _jsx(cmd.icon, { className: "size-3.5" }) }, cmd.key))) }), _jsx(ToolbarSeparator, {}), _jsxs(ToolbarGroup, { children: [_jsx(LinkControl, { editor: editor, targets: targets }), onOpenImage ? (_jsx(ToolbarButton, { label: translate('richText.image.add'), onClick: onOpenImage, children: _jsx(ImagePlus, { className: "size-3.5" }) })) : null, onOpenEmbed ? (_jsx(ToolbarButton, { label: translate('richText.embed.add'), onClick: onOpenEmbed, children: _jsx(Blocks, { className: "size-3.5" }) })) : null] }), _jsx("div", { className: "flex-1" }), _jsxs(ToolbarGroup, { children: [_jsx(ToolbarButton, { active: false, disabled: !state.canUndo, label: translate('richText.undo'), onClick: () => editor.chain().focus().undo().run(), children: _jsx(Undo2, { className: "size-3.5" }) }), _jsx(ToolbarButton, { active: false, disabled: !state.canRedo, label: translate('richText.redo'), onClick: () => editor.chain().focus().redo().run(), children: _jsx(Redo2, { className: "size-3.5" }) })] }), onToggleExpand ? (_jsxs(_Fragment, { children: [_jsx(ToolbarSeparator, {}), _jsx(ToolbarGroup, { children: _jsx(ToolbarButton, { active: expanded, label: expanded ? translate('richText.expand.collapse') : translate('richText.expand.expand'), onClick: onToggleExpand, children: expanded ? _jsx(Minimize2, { className: "size-3.5" }) : _jsx(Maximize2, { className: "size-3.5" }) }) })] })) : null] }));
52
+ return (_jsxs(Toolbar, { className: RICH_TEXT_TOOLBAR_CLASS, children: [_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: RICH_TEXT_MENU_TRIGGER_CLASS, "aria-label": blockStyleLabel(state.headingLevel), onMouseDown: (e) => e.preventDefault(), children: [_jsx(BlockStyleGlyph, { headingLevel: state.headingLevel }), _jsx(ChevronDown, { className: "size-3 opacity-60" })] }) }), _jsx(DropdownMenuContent, { align: "start", className: "min-w-40", children: BLOCK_STYLES.map((style) => (_jsxs(DropdownMenuItem, { onSelect: () => style.chain(editor.chain().focus()).run(), children: [_jsx(BlockStyleGlyph, { headingLevel: style.headingLevel }), ' ', blockStyleLabel(style.headingLevel)] }, style.headingLevel ?? 'paragraph'))) })] }), _jsx(FontSizeControl, { editor: editor, activeSize: state.fontSize }), _jsx(ToolbarSeparator, {}), _jsxs(ToolbarGroup, { children: [_jsx(ToolbarButton, { active: state.bold, label: translate('richText.bold'), onClick: () => editor.chain().focus().toggleBold().run(), children: _jsx(Bold, { className: "size-3.5" }) }), _jsx(ToolbarButton, { active: state.italic, label: translate('richText.italic'), onClick: () => editor.chain().focus().toggleItalic().run(), children: _jsx(Italic, { className: "size-3.5" }) }), _jsx(ToolbarButton, { active: state.underline, label: translate('richText.underline'), onClick: () => editor.chain().focus().toggleUnderline().run(), children: _jsx(Underline, { className: "size-3.5" }) }), _jsx(ToolbarButton, { active: state.strike, label: translate('richText.strike'), onClick: () => editor.chain().focus().toggleStrike().run(), children: _jsx(Strikethrough, { className: "size-3.5" }) }), _jsx(ToolbarButton, { active: state.code, label: translate('richText.code'), onClick: () => editor.chain().focus().toggleCode().run(), children: _jsx(Code, { className: "size-3.5" }) })] }), _jsx(ToolbarSeparator, {}), _jsx(ToolbarGroup, { children: BLOCK_COMMANDS.map((cmd) => (_jsx(ToolbarButton, { active: isBlockCommandActive(cmd, state), label: translate(cmd.labelKey), onClick: () => cmd.chain(editor.chain().focus()).run(), children: _jsx(cmd.icon, { className: "size-3.5" }) }, cmd.key))) }), _jsx(ToolbarSeparator, {}), _jsxs(ToolbarGroup, { children: [_jsx(LinkControl, { editor: editor, targets: targets }), onOpenImage ? (_jsx(ToolbarButton, { label: translate('richText.image.add'), onClick: onOpenImage, children: _jsx(ImagePlus, { className: "size-3.5" }) })) : null, onOpenEmbed ? (_jsx(ToolbarButton, { label: translate('richText.embed.add'), onClick: onOpenEmbed, children: _jsx(Blocks, { className: "size-3.5" }) })) : null] }), _jsx("div", { className: "flex-1" }), _jsxs(ToolbarGroup, { children: [_jsx(ToolbarButton, { active: false, disabled: !state.canUndo, label: translate('richText.undo'), onClick: () => editor.chain().focus().undo().run(), children: _jsx(Undo2, { className: "size-3.5" }) }), _jsx(ToolbarButton, { active: false, disabled: !state.canRedo, label: translate('richText.redo'), onClick: () => editor.chain().focus().redo().run(), children: _jsx(Redo2, { className: "size-3.5" }) })] }), onToggleExpand ? (_jsxs(_Fragment, { children: [_jsx(ToolbarSeparator, {}), _jsx(ToolbarGroup, { children: _jsx(ToolbarButton, { active: expanded, label: expanded ? translate('richText.expand.collapse') : translate('richText.expand.expand'), onClick: onToggleExpand, children: expanded ? _jsx(Minimize2, { className: "size-3.5" }) : _jsx(Maximize2, { className: "size-3.5" }) }) })] })) : null] }));
41
53
  }
42
54
  //# sourceMappingURL=toolbar.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"toolbar.js","sourceRoot":"","sources":["../../../../src/components/cms/rich-text/toolbar.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEditorState } from '@tiptap/react'\nimport type { Editor } from '@tiptap/react'\nimport {\n Blocks,\n Bold,\n ChevronDown,\n Code,\n ImagePlus,\n Italic,\n Maximize2,\n Minimize2,\n Pilcrow,\n Redo2,\n Strikethrough,\n Underline,\n Undo2,\n} from 'lucide-react'\nimport {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n Toolbar,\n ToolbarGroup,\n ToolbarSeparator,\n} from '@elytracms/studio/ui'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { ToolbarButton } from './toolbar-button'\nimport { LinkControl } from './link-control'\nimport type { LinkTarget } from './link-control'\nimport { toolbarStateFromEditor } from './toolbar-state'\nimport { BLOCK_COMMANDS, isBlockCommandActive } from './block-commands'\n\n/**\n * The toolbar container classes (EC-391). The load-bearing part is the height\n * contract: `h-auto min-h-10` (NOT a fixed `h-10`/`h-11`) so that when the many\n * controls wrap at narrow inspector widths the strip GROWS and reserves its real\n * layout height — the editable content always starts below it. A fixed height plus\n * `flex-wrap` was the bug: wrapped rows overflowed the locked box and painted over\n * the prose, so the buttons were un-hittable. `py-1` only bites once wrapped (a\n * single row is governed by `min-h-10` + `items-center`), padding the stacked rows.\n * Pinned by `toolbar-layout.test.ts`.\n */\nexport const RICH_TEXT_TOOLBAR_CLASS =\n 'h-auto min-h-10 flex-wrap gap-0.5 rounded-none border-x-0 border-t-0 bg-muted/30 px-1.5 py-1'\n\ninterface RichTextToolbarProps {\n editor: Editor\n /** Internal-link destinations across the workspace (empty ⇒ external-only). */\n targets: LinkTarget[]\n /** Open the shared image picker (omitted ⇒ no image button). */\n onOpenImage?: () => void\n /** Open the shared component-embed picker (omitted ⇒ no embed button). */\n onOpenEmbed?: () => void\n /** EC-388: whether the editor is currently in its expanded (sheet) surface. */\n expanded?: boolean\n /** EC-388: toggle the expanded editing surface (omitted ⇒ no expand affordance). */\n onToggleExpand?: () => void\n}\n\n/**\n * The CMS rich-text toolbar (EC-314) — a compact, Notion-grade control strip that\n * reads its active/enabled state reactively from the editor (`useEditorState`) so a\n * pressed control always mirrors the caret. Every button prevents the default\n * mousedown so clicking it never steals the editor selection.\n */\nexport function RichTextToolbar({\n editor,\n targets,\n onOpenImage,\n onOpenEmbed,\n expanded = false,\n onToggleExpand,\n}: RichTextToolbarProps) {\n // The selector delegates to a pure, NULL-SAFE projection: `useEditorState` runs\n // it through an external store that React can fire against a destroyed/pre-init\n // editor (concurrent teardown, the EC-322 lazy boundary), where `editor.can()`\n // would throw on TipTap v3's nulled `commandManager`. `toolbarStateFromEditor`\n // returns the disabled shape in that window instead of crashing the toolbar.\n const state = useEditorState({\n editor,\n selector: ({ editor }) => toolbarStateFromEditor(editor),\n })\n\n const styleLabel =\n state.headingLevel != null\n ? translate('richText.heading', { level: state.headingLevel })\n : translate('richText.paragraph')\n\n return (\n <Toolbar className={RICH_TEXT_TOOLBAR_CLASS}>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-7 gap-1 px-2 font-medium\"\n onMouseDown={(e) => e.preventDefault()}\n >\n {styleLabel}\n <ChevronDown className=\"size-3 opacity-60\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"min-w-40\">\n <DropdownMenuItem onSelect={() => editor.chain().focus().setParagraph().run()}>\n <Pilcrow className=\"size-3.5\" /> {translate('richText.paragraph')}\n </DropdownMenuItem>\n {([1, 2, 3] as const).map((level) => (\n <DropdownMenuItem\n key={level}\n onSelect={() => editor.chain().focus().toggleHeading({ level }).run()}\n >\n <span className=\"w-3.5 text-center text-xs font-semibold\">H{level}</span>{' '}\n {translate('richText.heading', { level })}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n\n <ToolbarSeparator />\n\n <ToolbarGroup>\n <ToolbarButton\n active={state.bold}\n label={translate('richText.bold')}\n onClick={() => editor.chain().focus().toggleBold().run()}\n >\n <Bold className=\"size-3.5\" />\n </ToolbarButton>\n <ToolbarButton\n active={state.italic}\n label={translate('richText.italic')}\n onClick={() => editor.chain().focus().toggleItalic().run()}\n >\n <Italic className=\"size-3.5\" />\n </ToolbarButton>\n <ToolbarButton\n active={state.underline}\n label={translate('richText.underline')}\n onClick={() => editor.chain().focus().toggleUnderline().run()}\n >\n <Underline className=\"size-3.5\" />\n </ToolbarButton>\n <ToolbarButton\n active={state.strike}\n label={translate('richText.strike')}\n onClick={() => editor.chain().focus().toggleStrike().run()}\n >\n <Strikethrough className=\"size-3.5\" />\n </ToolbarButton>\n <ToolbarButton\n active={state.code}\n label={translate('richText.code')}\n onClick={() => editor.chain().focus().toggleCode().run()}\n >\n <Code className=\"size-3.5\" />\n </ToolbarButton>\n </ToolbarGroup>\n\n <ToolbarSeparator />\n\n <ToolbarGroup>\n {/* The shared table (EC-328) — the SAME descriptors `buildSlashItems`\n derives its bulletList/orderedList/blockquote/codeBlock/divider items from. */}\n {BLOCK_COMMANDS.map((cmd) => (\n <ToolbarButton\n key={cmd.key}\n active={isBlockCommandActive(cmd, state)}\n label={translate(cmd.labelKey)}\n onClick={() => cmd.chain(editor.chain().focus()).run()}\n >\n <cmd.icon className=\"size-3.5\" />\n </ToolbarButton>\n ))}\n </ToolbarGroup>\n\n <ToolbarSeparator />\n\n <ToolbarGroup>\n <LinkControl editor={editor} targets={targets} />\n {onOpenImage ? (\n <ToolbarButton label={translate('richText.image.add')} onClick={onOpenImage}>\n <ImagePlus className=\"size-3.5\" />\n </ToolbarButton>\n ) : null}\n {onOpenEmbed ? (\n <ToolbarButton label={translate('richText.embed.add')} onClick={onOpenEmbed}>\n <Blocks className=\"size-3.5\" />\n </ToolbarButton>\n ) : null}\n </ToolbarGroup>\n\n <div className=\"flex-1\" />\n\n <ToolbarGroup>\n <ToolbarButton\n active={false}\n disabled={!state.canUndo}\n label={translate('richText.undo')}\n onClick={() => editor.chain().focus().undo().run()}\n >\n <Undo2 className=\"size-3.5\" />\n </ToolbarButton>\n <ToolbarButton\n active={false}\n disabled={!state.canRedo}\n label={translate('richText.redo')}\n onClick={() => editor.chain().focus().redo().run()}\n >\n <Redo2 className=\"size-3.5\" />\n </ToolbarButton>\n </ToolbarGroup>\n\n {/* EC-388: the expand/collapse affordance — moves with the toolbar into the\n expanded sheet (where it reads as \"collapse\") and back to the inline\n editor (where it reads as \"expand\"). Same editor instance, same value\n flow; no separate save/cancel. */}\n {onToggleExpand ? (\n <>\n <ToolbarSeparator />\n <ToolbarGroup>\n <ToolbarButton\n active={expanded}\n label={\n expanded ? translate('richText.expand.collapse') : translate('richText.expand.expand')\n }\n onClick={onToggleExpand}\n >\n {expanded ? <Minimize2 className=\"size-3.5\" /> : <Maximize2 className=\"size-3.5\" />}\n </ToolbarButton>\n </ToolbarGroup>\n </>\n ) : null}\n </Toolbar>\n )\n}\n"]}
1
+ {"version":3,"file":"toolbar.js","sourceRoot":"","sources":["../../../../src/components/cms/rich-text/toolbar.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEditorState } from '@tiptap/react'\nimport type { Editor } from '@tiptap/react'\nimport {\n Blocks,\n Bold,\n ChevronDown,\n Code,\n ImagePlus,\n Italic,\n Maximize2,\n Minimize2,\n Redo2,\n Strikethrough,\n Underline,\n Undo2,\n} from 'lucide-react'\nimport {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n Toolbar,\n ToolbarGroup,\n ToolbarSeparator,\n} from '@elytracms/studio/ui'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { ToolbarButton } from './toolbar-button'\nimport { LinkControl } from './link-control'\nimport type { LinkTarget } from './link-control'\nimport { toolbarStateFromEditor } from './toolbar-state'\nimport { BLOCK_COMMANDS, isBlockCommandActive } from './block-commands'\nimport { BLOCK_STYLES, BlockStyleGlyph, blockStyleLabel } from './block-style'\nimport { FontSizeControl } from './font-size-control'\n\n/**\n * The toolbar container classes (EC-391). The load-bearing part is the height\n * contract: `h-auto min-h-10` (NOT a fixed `h-10`/`h-11`) so that when the many\n * controls wrap at narrow inspector widths the strip GROWS and reserves its real\n * layout height — the editable content always starts below it. A fixed height plus\n * `flex-wrap` was the bug: wrapped rows overflowed the locked box and painted over\n * the prose, so the buttons were un-hittable. `py-1` only bites once wrapped (a\n * single row is governed by `min-h-10` + `items-center`), padding the stacked rows.\n * Pinned by `toolbar-layout.test.ts`.\n */\nexport const RICH_TEXT_TOOLBAR_CLASS =\n 'h-auto min-h-10 flex-wrap gap-0.5 rounded-none border-x-0 border-t-0 bg-muted/30 px-1.5 py-1'\n\n/**\n * The block-style dropdown trigger's class (EC-418). The load-bearing part is the\n * FIXED width (`w-12`): the trigger shows the active style's icon glyph (not its\n * variable-width localized label — \"Absatz\" ≪ \"Überschrift 2\"), so caret movement\n * across Absatz/H1/H2/H3 can never change the trigger's width and reflow the wrapped\n * strip beneath the cursor (the reported German-locale defect). `justify-between`\n * seats the glyph and the ChevronDown in that fixed box. Every other control on the\n * strip is already a fixed `size-7` square (`ToolbarButton`, `LinkControl`) whose\n * active state only recolors (a `secondary` border sits inside the box-border square,\n * never resizing it) — so this trigger was the sole selection-variable width.\n * Pinned by `toolbar-layout.test.ts`.\n */\nexport const RICH_TEXT_MENU_TRIGGER_CLASS = 'h-7 w-12 justify-between gap-1 px-2'\n\ninterface RichTextToolbarProps {\n editor: Editor\n /** Internal-link destinations across the workspace (empty ⇒ external-only). */\n targets: LinkTarget[]\n /** Open the shared image picker (omitted ⇒ no image button). */\n onOpenImage?: () => void\n /** Open the shared component-embed picker (omitted ⇒ no embed button). */\n onOpenEmbed?: () => void\n /** EC-388: whether the editor is currently in its expanded (sheet) surface. */\n expanded?: boolean\n /** EC-388: toggle the expanded editing surface (omitted ⇒ no expand affordance). */\n onToggleExpand?: () => void\n}\n\n/**\n * The CMS rich-text toolbar (EC-314) — a compact, Notion-grade control strip that\n * reads its active/enabled state reactively from the editor (`useEditorState`) so a\n * pressed control always mirrors the caret. Every button prevents the default\n * mousedown so clicking it never steals the editor selection.\n */\nexport function RichTextToolbar({\n editor,\n targets,\n onOpenImage,\n onOpenEmbed,\n expanded = false,\n onToggleExpand,\n}: RichTextToolbarProps) {\n // The selector delegates to a pure, NULL-SAFE projection: `useEditorState` runs\n // it through an external store that React can fire against a destroyed/pre-init\n // editor (concurrent teardown, the EC-322 lazy boundary), where `editor.can()`\n // would throw on TipTap v3's nulled `commandManager`. `toolbarStateFromEditor`\n // returns the disabled shape in that window instead of crashing the toolbar.\n const state = useEditorState({\n editor,\n selector: ({ editor }) => toolbarStateFromEditor(editor),\n })\n\n return (\n <Toolbar className={RICH_TEXT_TOOLBAR_CLASS}>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className={RICH_TEXT_MENU_TRIGGER_CLASS}\n // The visible label moved into the opened menu (EC-418) — the trigger keeps\n // an accessible name for the ACTIVE style from the same catalog keys.\n aria-label={blockStyleLabel(state.headingLevel)}\n onMouseDown={(e) => e.preventDefault()}\n >\n <BlockStyleGlyph headingLevel={state.headingLevel} />\n <ChevronDown className=\"size-3 opacity-60\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"min-w-40\">\n {BLOCK_STYLES.map((style) => (\n <DropdownMenuItem\n key={style.headingLevel ?? 'paragraph'}\n onSelect={() => style.chain(editor.chain().focus()).run()}\n >\n <BlockStyleGlyph headingLevel={style.headingLevel} />{' '}\n {blockStyleLabel(style.headingLevel)}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n\n <FontSizeControl editor={editor} activeSize={state.fontSize} />\n\n <ToolbarSeparator />\n\n <ToolbarGroup>\n <ToolbarButton\n active={state.bold}\n label={translate('richText.bold')}\n onClick={() => editor.chain().focus().toggleBold().run()}\n >\n <Bold className=\"size-3.5\" />\n </ToolbarButton>\n <ToolbarButton\n active={state.italic}\n label={translate('richText.italic')}\n onClick={() => editor.chain().focus().toggleItalic().run()}\n >\n <Italic className=\"size-3.5\" />\n </ToolbarButton>\n <ToolbarButton\n active={state.underline}\n label={translate('richText.underline')}\n onClick={() => editor.chain().focus().toggleUnderline().run()}\n >\n <Underline className=\"size-3.5\" />\n </ToolbarButton>\n <ToolbarButton\n active={state.strike}\n label={translate('richText.strike')}\n onClick={() => editor.chain().focus().toggleStrike().run()}\n >\n <Strikethrough className=\"size-3.5\" />\n </ToolbarButton>\n <ToolbarButton\n active={state.code}\n label={translate('richText.code')}\n onClick={() => editor.chain().focus().toggleCode().run()}\n >\n <Code className=\"size-3.5\" />\n </ToolbarButton>\n </ToolbarGroup>\n\n <ToolbarSeparator />\n\n <ToolbarGroup>\n {/* The shared table (EC-328) — the SAME descriptors `buildSlashItems`\n derives its bulletList/orderedList/blockquote/codeBlock/divider items from. */}\n {BLOCK_COMMANDS.map((cmd) => (\n <ToolbarButton\n key={cmd.key}\n active={isBlockCommandActive(cmd, state)}\n label={translate(cmd.labelKey)}\n onClick={() => cmd.chain(editor.chain().focus()).run()}\n >\n <cmd.icon className=\"size-3.5\" />\n </ToolbarButton>\n ))}\n </ToolbarGroup>\n\n <ToolbarSeparator />\n\n <ToolbarGroup>\n <LinkControl editor={editor} targets={targets} />\n {onOpenImage ? (\n <ToolbarButton label={translate('richText.image.add')} onClick={onOpenImage}>\n <ImagePlus className=\"size-3.5\" />\n </ToolbarButton>\n ) : null}\n {onOpenEmbed ? (\n <ToolbarButton label={translate('richText.embed.add')} onClick={onOpenEmbed}>\n <Blocks className=\"size-3.5\" />\n </ToolbarButton>\n ) : null}\n </ToolbarGroup>\n\n <div className=\"flex-1\" />\n\n <ToolbarGroup>\n <ToolbarButton\n active={false}\n disabled={!state.canUndo}\n label={translate('richText.undo')}\n onClick={() => editor.chain().focus().undo().run()}\n >\n <Undo2 className=\"size-3.5\" />\n </ToolbarButton>\n <ToolbarButton\n active={false}\n disabled={!state.canRedo}\n label={translate('richText.redo')}\n onClick={() => editor.chain().focus().redo().run()}\n >\n <Redo2 className=\"size-3.5\" />\n </ToolbarButton>\n </ToolbarGroup>\n\n {/* EC-388: the expand/collapse affordance — moves with the toolbar into the\n expanded sheet (where it reads as \"collapse\") and back to the inline\n editor (where it reads as \"expand\"). Same editor instance, same value\n flow; no separate save/cancel. */}\n {onToggleExpand ? (\n <>\n <ToolbarSeparator />\n <ToolbarGroup>\n <ToolbarButton\n active={expanded}\n label={\n expanded ? translate('richText.expand.collapse') : translate('richText.expand.expand')\n }\n onClick={onToggleExpand}\n >\n {expanded ? <Minimize2 className=\"size-3.5\" /> : <Maximize2 className=\"size-3.5\" />}\n </ToolbarButton>\n </ToolbarGroup>\n </>\n ) : null}\n </Toolbar>\n )\n}\n"]}
@@ -11,7 +11,7 @@ import { TransferToDocumentDialog } from '@elytracms/studio/components/component
11
11
  import { ReferencesPanel } from '@elytracms/studio/components/references/references-panel';
12
12
  import { InspectorSidebar } from '@elytracms/studio/components/inspector/inspector-sidebar';
13
13
  import { useSetBreadcrumb } from '@elytracms/studio/components/breadcrumb-context';
14
- import { translate } from '@elytracms/studio/lib/i18n';
14
+ import { localizedLabel, translate } from '@elytracms/studio/lib/i18n';
15
15
  import { Badge, Button, Code, Heading, Row, Spacer, Stack, TabButton, Text } from '@elytracms/studio/ui';
16
16
  import { cn } from '@elytracms/studio/lib/utils';
17
17
  /**
@@ -26,7 +26,7 @@ export function ComponentDetail({ projectId, componentId, }) {
26
26
  const manifest = studio.registry.getManifest(componentId);
27
27
  // EC-214: the component is the active record — name it in the global header
28
28
  // breadcrumb (under the Components section crumb). Unconditional (hooks rules).
29
- useSetBreadcrumb([{ label: manifest?.title ?? manifest?.id ?? componentId }]);
29
+ useSetBreadcrumb([{ label: localizedLabel(manifest?.title, manifest?.id ?? componentId) }]);
30
30
  if (!manifest) {
31
31
  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') })] }) }));
32
32
  }
@@ -38,7 +38,7 @@ function ComponentDetailBody({ projectId, studio, manifest, }) {
38
38
  const [transferOpen, setTransferOpen] = useState(false);
39
39
  const status = componentStatus(studio, manifest);
40
40
  const namespace = isPrimitive(manifest.id) ? 'base' : 'project';
41
- const title = manifest.title ?? manifest.id;
41
+ const title = localizedLabel(manifest.title, manifest.id);
42
42
  // The Preview tab's right inspector: editable Props + declared Slots. Shares the
43
43
  // exact frame the document editor uses (EC-224), so a prop edit re-renders the
44
44
  // preview live through the same control set documents use.
@@ -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 { useState } from 'react'\nimport { ArrowLeft, FilePlus2, Link2, ListTree, Play, SlidersHorizontal, SquareStack } from 'lucide-react'\nimport { isPrimitive } from '@elytracms/core/component-registry'\nimport type { ComponentManifest } from '@elytracms/core/component-registry'\nimport { Link, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router'\nimport { componentStatus, getStudioRegistry } from '@elytracms/studio/lib/registry'\nimport type { StudioRegistry } 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 {\n ComponentPreview,\n PropsEditorPane,\n SlotsInfoPane,\n usePreviewState,\n} from '@elytracms/studio/components/components/component-preview'\nimport { TransferToDocumentDialog } from '@elytracms/studio/components/components/transfer-dialog'\nimport { ReferencesPanel } from '@elytracms/studio/components/references/references-panel'\nimport { InspectorSidebar } from '@elytracms/studio/components/inspector/inspector-sidebar'\nimport type { InspectorPane } from '@elytracms/studio/components/inspector/inspector-sidebar'\nimport { useSetBreadcrumb } from '@elytracms/studio/components/breadcrumb-context'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { Badge, Button, Code, Heading, Row, Spacer, Stack, TabButton, Text } from '@elytracms/studio/ui'\nimport { cn } from '@elytracms/studio/lib/utils'\n\n/**\n * The component detail view (EC-050/052, overhauled in EC-320) — now on the CMS\n * shell: a header (title · namespace/category badges · id · status), a lens row of\n * tabs (Preview / Manifest / References — References-as-a-tab, EC-269), and, on the\n * Preview tab, the live editable preview beside the shared right {@link InspectorSidebar}\n * (Props / Slots). \"Use in document…\" transfers the current combination into a draft.\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). Unconditional (hooks rules).\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\">{translate('components.detail.notFound.body', { id: componentId })}</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 return <ComponentDetailBody key={manifest.id} projectId={projectId} studio={studio} manifest={manifest} />\n}\n\ntype DetailTab = 'preview' | 'manifest' | 'references'\n\nfunction ComponentDetailBody({\n projectId,\n studio,\n manifest,\n}: {\n projectId: string\n studio: StudioRegistry\n manifest: ComponentManifest\n}) {\n const preview = usePreviewState(manifest)\n const [tab, setTab] = useState<DetailTab>('preview')\n const [transferOpen, setTransferOpen] = useState(false)\n\n const status = componentStatus(studio, manifest)\n const namespace = isPrimitive(manifest.id) ? 'base' : 'project'\n const title = manifest.title ?? manifest.id\n\n // The Preview tab's right inspector: editable Props + declared Slots. Shares the\n // exact frame the document editor uses (EC-224), so a prop edit re-renders the\n // preview live through the same control set documents use.\n const panes: InspectorPane[] = [\n {\n id: 'props',\n label: translate('components.fieldInspector.props'),\n icon: <SlidersHorizontal className=\"size-3.5\" />,\n render: () => <PropsEditorPane manifest={manifest} state={preview} />,\n },\n {\n id: 'slots',\n label: translate('components.fieldInspector.slots'),\n icon: <SquareStack className=\"size-3.5\" />,\n render: () => <SlotsInfoPane manifest={manifest} />,\n },\n ]\n\n return (\n <div className=\"flex h-full min-h-0 flex-col\">\n {/* Mobile-only back link (the registry sidebar is hidden under md). */}\n <Link\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.components() }}\n className=\"inline-flex items-center gap-1 px-4 pt-3 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 {/* Header */}\n <div className=\"shrink-0 border-b border-border px-4 py-3 sm:px-6\">\n <Row gap=\"3\">\n <Row gap=\"2\" align=\"center\" className=\"min-w-0 flex-wrap\">\n <Heading level={1} size=\"h2\" className=\"truncate\">\n {title}\n </Heading>\n <Badge variant={namespace === 'project' ? 'primary' : 'outline'}>{namespace}</Badge>\n {manifest.category ? <Badge variant=\"outline\">{manifest.category}</Badge> : null}\n </Row>\n <Spacer />\n <ComponentStatusBadge status={status} />\n <Button size=\"sm\" onClick={() => setTransferOpen(true)} data-testid=\"use-in-document\">\n <FilePlus2 /> {translate('components.transfer.action')}\n </Button>\n </Row>\n <Row gap=\"2\" align=\"center\" className=\"mt-1\">\n <Code tone=\"muted\">{manifest.id}</Code>\n </Row>\n {manifest.description ? (\n <Text tone=\"muted\" size=\"sm\" className=\"mt-1 max-w-prose\">\n {manifest.description}\n </Text>\n ) : null}\n {status !== 'valid' ? (\n <Text size=\"sm\" className={cn('mt-1', status === 'invalid' ? 'text-destructive' : 'text-warning')}>\n {statusDescription(status)}\n </Text>\n ) : null}\n\n {/* Lens row — the tab set (mirrors the document editor's lens row). */}\n <Row gap=\"1\" align=\"center\" className=\"mt-3\">\n <TabButton active={tab === 'preview'} onClick={() => setTab('preview')}>\n <Play className=\"size-3\" />\n {translate('components.detail.tab.preview')}\n </TabButton>\n <TabButton active={tab === 'manifest'} onClick={() => setTab('manifest')}>\n <ListTree className=\"size-3\" />\n {translate('components.detail.tab.manifest')}\n </TabButton>\n <div className=\"mx-1 h-4 w-px bg-border\" aria-hidden />\n <TabButton active={tab === 'references'} onClick={() => setTab('references')}>\n <Link2 className=\"size-3\" />\n {translate('references.title')}\n </TabButton>\n </Row>\n </div>\n\n {/* Body */}\n {tab === 'preview' ? (\n <div className=\"flex min-h-0 flex-1 overflow-hidden\">\n <div className=\"min-h-0 flex-1 overflow-hidden\">\n <ComponentPreview manifest={manifest} studio={studio} state={preview} />\n </div>\n <InspectorSidebar panes={panes} className=\"w-[320px] shrink-0 border-l border-border\" />\n </div>\n ) : tab === 'manifest' ? (\n <div className=\"min-h-0 flex-1 overflow-auto p-4 sm:p-6\">\n <div className=\"mx-auto w-full max-w-4xl\">\n <Stack gap=\"6\">\n <FieldInspector manifest={manifest} />\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 </Stack>\n </div>\n </div>\n ) : (\n // EC-172/EC-269: inbound references over the reference index, as a tab.\n <div className=\"min-h-0 flex-1 overflow-auto p-4 sm:p-6\">\n <div className=\"mx-auto w-full max-w-2xl\">\n <ReferencesPanel projectId={projectId} target={{ type: 'component', id: manifest.id }} />\n </div>\n </div>\n )}\n\n <TransferToDocumentDialog\n projectId={projectId}\n manifest={manifest}\n node={preview.node}\n open={transferOpen}\n onOpenChange={setTransferOpen}\n />\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 { useState } from 'react'\nimport { ArrowLeft, FilePlus2, Link2, ListTree, Play, SlidersHorizontal, SquareStack } from 'lucide-react'\nimport { isPrimitive } from '@elytracms/core/component-registry'\nimport type { ComponentManifest } from '@elytracms/core/component-registry'\nimport { Link, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router'\nimport { componentStatus, getStudioRegistry } from '@elytracms/studio/lib/registry'\nimport type { StudioRegistry } 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 {\n ComponentPreview,\n PropsEditorPane,\n SlotsInfoPane,\n usePreviewState,\n} from '@elytracms/studio/components/components/component-preview'\nimport { TransferToDocumentDialog } from '@elytracms/studio/components/components/transfer-dialog'\nimport { ReferencesPanel } from '@elytracms/studio/components/references/references-panel'\nimport { InspectorSidebar } from '@elytracms/studio/components/inspector/inspector-sidebar'\nimport type { InspectorPane } from '@elytracms/studio/components/inspector/inspector-sidebar'\nimport { useSetBreadcrumb } from '@elytracms/studio/components/breadcrumb-context'\nimport { localizedLabel, translate } from '@elytracms/studio/lib/i18n'\nimport { Badge, Button, Code, Heading, Row, Spacer, Stack, TabButton, Text } from '@elytracms/studio/ui'\nimport { cn } from '@elytracms/studio/lib/utils'\n\n/**\n * The component detail view (EC-050/052, overhauled in EC-320) — now on the CMS\n * shell: a header (title · namespace/category badges · id · status), a lens row of\n * tabs (Preview / Manifest / References — References-as-a-tab, EC-269), and, on the\n * Preview tab, the live editable preview beside the shared right {@link InspectorSidebar}\n * (Props / Slots). \"Use in document…\" transfers the current combination into a draft.\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). Unconditional (hooks rules).\n useSetBreadcrumb([{ label: localizedLabel(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\">{translate('components.detail.notFound.body', { id: componentId })}</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 return <ComponentDetailBody key={manifest.id} projectId={projectId} studio={studio} manifest={manifest} />\n}\n\ntype DetailTab = 'preview' | 'manifest' | 'references'\n\nfunction ComponentDetailBody({\n projectId,\n studio,\n manifest,\n}: {\n projectId: string\n studio: StudioRegistry\n manifest: ComponentManifest\n}) {\n const preview = usePreviewState(manifest)\n const [tab, setTab] = useState<DetailTab>('preview')\n const [transferOpen, setTransferOpen] = useState(false)\n\n const status = componentStatus(studio, manifest)\n const namespace = isPrimitive(manifest.id) ? 'base' : 'project'\n const title = localizedLabel(manifest.title, manifest.id)\n\n // The Preview tab's right inspector: editable Props + declared Slots. Shares the\n // exact frame the document editor uses (EC-224), so a prop edit re-renders the\n // preview live through the same control set documents use.\n const panes: InspectorPane[] = [\n {\n id: 'props',\n label: translate('components.fieldInspector.props'),\n icon: <SlidersHorizontal className=\"size-3.5\" />,\n render: () => <PropsEditorPane manifest={manifest} state={preview} />,\n },\n {\n id: 'slots',\n label: translate('components.fieldInspector.slots'),\n icon: <SquareStack className=\"size-3.5\" />,\n render: () => <SlotsInfoPane manifest={manifest} />,\n },\n ]\n\n return (\n <div className=\"flex h-full min-h-0 flex-col\">\n {/* Mobile-only back link (the registry sidebar is hidden under md). */}\n <Link\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.components() }}\n className=\"inline-flex items-center gap-1 px-4 pt-3 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 {/* Header */}\n <div className=\"shrink-0 border-b border-border px-4 py-3 sm:px-6\">\n <Row gap=\"3\">\n <Row gap=\"2\" align=\"center\" className=\"min-w-0 flex-wrap\">\n <Heading level={1} size=\"h2\" className=\"truncate\">\n {title}\n </Heading>\n <Badge variant={namespace === 'project' ? 'primary' : 'outline'}>{namespace}</Badge>\n {manifest.category ? <Badge variant=\"outline\">{manifest.category}</Badge> : null}\n </Row>\n <Spacer />\n <ComponentStatusBadge status={status} />\n <Button size=\"sm\" onClick={() => setTransferOpen(true)} data-testid=\"use-in-document\">\n <FilePlus2 /> {translate('components.transfer.action')}\n </Button>\n </Row>\n <Row gap=\"2\" align=\"center\" className=\"mt-1\">\n <Code tone=\"muted\">{manifest.id}</Code>\n </Row>\n {manifest.description ? (\n <Text tone=\"muted\" size=\"sm\" className=\"mt-1 max-w-prose\">\n {manifest.description}\n </Text>\n ) : null}\n {status !== 'valid' ? (\n <Text size=\"sm\" className={cn('mt-1', status === 'invalid' ? 'text-destructive' : 'text-warning')}>\n {statusDescription(status)}\n </Text>\n ) : null}\n\n {/* Lens row — the tab set (mirrors the document editor's lens row). */}\n <Row gap=\"1\" align=\"center\" className=\"mt-3\">\n <TabButton active={tab === 'preview'} onClick={() => setTab('preview')}>\n <Play className=\"size-3\" />\n {translate('components.detail.tab.preview')}\n </TabButton>\n <TabButton active={tab === 'manifest'} onClick={() => setTab('manifest')}>\n <ListTree className=\"size-3\" />\n {translate('components.detail.tab.manifest')}\n </TabButton>\n <div className=\"mx-1 h-4 w-px bg-border\" aria-hidden />\n <TabButton active={tab === 'references'} onClick={() => setTab('references')}>\n <Link2 className=\"size-3\" />\n {translate('references.title')}\n </TabButton>\n </Row>\n </div>\n\n {/* Body */}\n {tab === 'preview' ? (\n <div className=\"flex min-h-0 flex-1 overflow-hidden\">\n <div className=\"min-h-0 flex-1 overflow-hidden\">\n <ComponentPreview manifest={manifest} studio={studio} state={preview} />\n </div>\n <InspectorSidebar panes={panes} className=\"w-[320px] shrink-0 border-l border-border\" />\n </div>\n ) : tab === 'manifest' ? (\n <div className=\"min-h-0 flex-1 overflow-auto p-4 sm:p-6\">\n <div className=\"mx-auto w-full max-w-4xl\">\n <Stack gap=\"6\">\n <FieldInspector manifest={manifest} />\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 </Stack>\n </div>\n </div>\n ) : (\n // EC-172/EC-269: inbound references over the reference index, as a tab.\n <div className=\"min-h-0 flex-1 overflow-auto p-4 sm:p-6\">\n <div className=\"mx-auto w-full max-w-2xl\">\n <ReferencesPanel projectId={projectId} target={{ type: 'component', id: manifest.id }} />\n </div>\n </div>\n )}\n\n <TransferToDocumentDialog\n projectId={projectId}\n manifest={manifest}\n node={preview.node}\n open={transferOpen}\n onOpenChange={setTransferOpen}\n />\n </div>\n )\n}\n"]}
@@ -69,7 +69,8 @@ export declare class PreviewErrorBoundary extends Component<{
69
69
  * The EC-191 fallback panel — component name + "preview unavailable" + the error.
70
70
  * Rendered INTO the preview iframe (which carries only the project stylesheet, and
71
71
  * may carry none in tests), so it uses inline styles rather than studio UI classes
72
- * — matching the canvas's own in-iframe placeholder convention.
72
+ * — the EC-414 AD-B chrome contract, with the `.ec-chrome` containment recipe on
73
+ * its root (walked by the chrome contract test).
73
74
  */
74
75
  export declare function PreviewUnavailable({ displayName, error }: {
75
76
  displayName: string;
@@ -9,6 +9,8 @@ import { previewSpecs } from '@elytracms/studio/lib/registry/preview';
9
9
  import { Badge, Button, Code, Field, Row, Spacer, Stack, TabButton, Text } from '@elytracms/studio/ui';
10
10
  import { localizedLabel, translate } from '@elytracms/studio/lib/i18n';
11
11
  import { cn } from '@elytracms/studio/lib/utils';
12
+ import { resolveDeploymentCanvasTheme } from '@elytracms/studio/lib/workspace';
13
+ import { wireCanvasChrome } from '../builder/canvas-chrome.js';
12
14
  import { getCanvasStylesheetUrl } from '../builder/canvas-stylesheet.js';
13
15
  import { useCanvasViewports, viewportWidth } from '../builder/canvas-breakpoints.js';
14
16
  import { PropValueControl } from '../cms/prop-fields.js';
@@ -64,7 +66,7 @@ export function ComponentPreview({ manifest, studio, state, }) {
64
66
  const ctx = useMemo(() => previewContext(studio), [studio]);
65
67
  const serverOnly = manifest.clientRenderable === false;
66
68
  const status = componentStatus(studio, manifest);
67
- const displayName = manifest.title ?? manifest.id;
69
+ const displayName = localizedLabel(manifest.title, manifest.id);
68
70
  // EC-330: the same config-sourced breakpoint set the builder canvas toolbar
69
71
  // offers (`canvas-breakpoints.ts`) — reused, not redefined, so a preview and
70
72
  // the real canvas never disagree about the site's responsive widths.
@@ -97,20 +99,23 @@ function ServerOnlyNotice() {
97
99
  const MIN_PREVIEW_HEIGHT = 360;
98
100
  /**
99
101
  * The live preview render surface. Reuses the BuilderCanvas styling mechanism
100
- * (EC-061, `canvas.tsx`): the component renders inside an ISOLATED same-origin
101
- * iframe that `<link>`s the project's canvas stylesheet
102
- * (`getCanvasStylesheetUrl()` — the consuming app's delivery CSS + studio CSS), so
103
- * a component built with the site's Tailwind theme previews with the site's styles,
104
- * exactly as it does on the canvas and in delivery. Using the iframe (not the
105
- * studio DOM) is what keeps the delivery CSS scoped and off the studio chrome.
102
+ * (EC-061, `canvas.tsx`) — since EC-414 through the SAME code path, `wireCanvasChrome`
103
+ * (closing the EC-389 follow-up): the component renders inside an ISOLATED
104
+ * same-origin iframe that `<link>`s the project's canvas stylesheet
105
+ * (`getCanvasStylesheetUrl()` — the consumer's theme entry; in the legacy merged
106
+ * world also the studio CSS), so a component built with the site's Tailwind theme
107
+ * previews with the site's styles, exactly as it does on the canvas and in
108
+ * delivery. Using the iframe (not the studio DOM) is what keeps the delivery CSS
109
+ * scoped and off the studio chrome.
106
110
  *
107
111
  * Unlike the builder canvas, this iframe's document is deliberately left OUT of
108
112
  * the studio's own dark/light class: this is a standalone-component reference
109
113
  * surface (not a full page), so its own negative space around the component must
110
114
  * read as a light, site-like backdrop — never the studio chrome's current theme
111
115
  * (a black frame is exactly what leaks through when the studio is dark-themed and
112
- * the iframe root inherits that class). The canvas stylesheet's `:root` (light)
113
- * tokens supply that backdrop for free once the `.dark` class is never added here.
116
+ * the iframe root inherits that class). The chrome's world probe supplies that
117
+ * backdrop: the neutral backdrop rules in the new world, the studio `:root`
118
+ * (light) tokens in the legacy one.
114
119
  *
115
120
  * Sizing: width is driven by the caller (the breakpoint selector); height is
116
121
  * measured live from the rendered content via `ResizeObserver` (EC-330) so a
@@ -128,21 +133,14 @@ function ComponentPreviewFrame({ node, ctx, displayName, width, }) {
128
133
  const d = iframeRef.current?.contentDocument;
129
134
  if (!d || !d.body)
130
135
  return;
131
- // Deliberately no `.dark` here (see the surface note above) — the light
132
- // `:root` tokens from the injected stylesheet are the intended backdrop.
133
- // Unset stylesheet (tests / an app that never called
134
- // `setCanvasStylesheetUrl`) → skip the link.
135
- const appCss = getCanvasStylesheetUrl();
136
- if (appCss && !d.getElementById('ec-app-css')) {
137
- const link = d.createElement('link');
138
- link.id = 'ec-app-css';
139
- link.rel = 'stylesheet';
140
- link.href = appCss;
141
- d.head.appendChild(link);
142
- }
143
- d.body.className = 'bg-background text-foreground font-sans';
144
- d.body.style.margin = '0';
145
- d.body.style.padding = '24px';
136
+ // ONE code path with the builder canvas (EC-414 AD-B item 4): stylesheet
137
+ // link + chrome css + consumer canvas theme + the world probe. No kit
138
+ // tokens here — this is a registry-level reference surface, not a project
139
+ // page. The dev theme notice is the builder canvas's job, not this pane's.
140
+ wireCanvasChrome(d, {
141
+ stylesheetUrl: getCanvasStylesheetUrl(),
142
+ theme: resolveDeploymentCanvasTheme(),
143
+ });
146
144
  setDoc(d);
147
145
  }, []);
148
146
  // Handle the already-loaded case (srcDoc can load before onLoad attaches).
@@ -208,10 +206,11 @@ export class PreviewErrorBoundary extends Component {
208
206
  * The EC-191 fallback panel — component name + "preview unavailable" + the error.
209
207
  * Rendered INTO the preview iframe (which carries only the project stylesheet, and
210
208
  * may carry none in tests), so it uses inline styles rather than studio UI classes
211
- * — matching the canvas's own in-iframe placeholder convention.
209
+ * — the EC-414 AD-B chrome contract, with the `.ec-chrome` containment recipe on
210
+ * its root (walked by the chrome contract test).
212
211
  */
213
212
  export function PreviewUnavailable({ displayName, error }) {
214
- return (_jsxs("div", { "data-preview-unavailable": true, style: {
213
+ return (_jsxs("div", { "data-preview-unavailable": true, className: "ec-chrome", style: {
215
214
  boxSizing: 'border-box',
216
215
  maxWidth: '42rem',
217
216
  margin: '0 auto',
@@ -1 +1 @@
1
- {"version":3,"file":"component-preview.js","sourceRoot":"","sources":["../../../src/components/components/component-preview.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Component, useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { ReactNode } from 'react'\nimport { createPortal } from 'react-dom'\nimport { MonitorOff, RotateCcw } from 'lucide-react'\nimport { renderNode } from '@elytracms/core/runtime-renderer'\nimport type { RenderContext } from '@elytracms/core/runtime-renderer'\nimport { staticProp } from '@elytracms/core/project-graph'\nimport type { ComponentNode, JsonValue } from '@elytracms/core/project-graph'\nimport type { ComponentManifest, PropField } from '@elytracms/core/component-registry'\nimport { componentStatus, previewContext } from '@elytracms/studio/lib/registry'\nimport type { StudioRegistry } from '@elytracms/studio/lib/registry'\nimport { previewSpecs } from '@elytracms/studio/lib/registry/preview'\nimport type { PreviewSpec } from '@elytracms/studio/lib/registry/preview'\nimport { Badge, Button, Code, Field, Row, Spacer, Stack, TabButton, Text } from '@elytracms/studio/ui'\nimport { localizedLabel, translate } from '@elytracms/studio/lib/i18n'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { getCanvasStylesheetUrl } from '../builder/canvas-stylesheet'\nimport { useCanvasViewports, viewportWidth } from '../builder/canvas-breakpoints'\nimport type { ViewportOption } from '../builder/canvas-breakpoints'\nimport { PropValueControl } from '../cms/prop-fields'\n\n/**\n * EC-320 — the editable component preview. A component's declared preview states\n * (fixtures) select the SAMPLE STATE (slot content, base props); on top of that\n * the user edits individual prop values in the Props sidebar and the preview\n * re-renders live through the SAME runtime-renderer path the Builder and export\n * use (EC-054). Slots follow the selected fixture — full slot-tree editing is out\n * of scope for this reference surface (that's the composition editor's job); the\n * Slots pane documents what a component accepts and which state supplies content.\n */\n\nexport interface PreviewState {\n specs: PreviewSpec[]\n index: number\n setIndex: (i: number) => void\n /** Per-prop static-value overrides applied over the selected fixture. */\n overrides: Record<string, JsonValue>\n setOverride: (name: string, value: JsonValue) => void\n clearOverride: (name: string) => void\n resetAll: () => void\n dirty: boolean\n /** The live node: the selected fixture with prop overrides applied. */\n node: ComponentNode\n}\n\n/** Preview state for a manifest: the fixture selection + the live prop overrides. */\nexport function usePreviewState(manifest: ComponentManifest): PreviewState {\n const specs = useMemo(() => previewSpecs(manifest), [manifest])\n const [index, setIndexRaw] = useState(0)\n const [overrides, setOverrides] = useState<Record<string, JsonValue>>({})\n\n // Switching preview state resets prop edits — they were relative to the old state.\n const setIndex = (i: number) => {\n setIndexRaw(i)\n setOverrides({})\n }\n const setOverride = (name: string, value: JsonValue) =>\n setOverrides((o) => ({ ...o, [name]: value }))\n const clearOverride = (name: string) =>\n setOverrides((o) => {\n const next = { ...o }\n delete next[name]\n return next\n })\n const resetAll = () => setOverrides({})\n\n const base = specs[Math.min(index, specs.length - 1)]?.node\n const node = useMemo<ComponentNode>(() => {\n const fixture = base ?? { id: `preview-${manifest.id}`, componentId: manifest.id, props: {} }\n const props = { ...(fixture.props ?? {}) }\n for (const [name, value] of Object.entries(overrides)) props[name] = staticProp(value)\n return { ...fixture, props }\n }, [base, overrides, manifest.id])\n\n return {\n specs,\n index: Math.min(index, Math.max(specs.length - 1, 0)),\n setIndex,\n overrides,\n setOverride,\n clearOverride,\n resetAll,\n dirty: Object.keys(overrides).length > 0,\n node,\n }\n}\n\n/** Re-id a preview node into the canvas `node-<n>` namespace for embedding (transfer). */\nexport function embedNodeFrom(node: ComponentNode, id: string): ComponentNode {\n return { ...node, id }\n}\n\n/**\n * The live preview surface: the fixture-state selector (when a component declares\n * more than one) plus the rendered node. Server-only components (EC-191\n * `clientRenderable: false`) can't run on the client-rendered canvas, so they show\n * a documented fallback rather than risk a crash; a missing implementation falls\n * back through the renderer itself (the incompatible state).\n */\nexport function ComponentPreview({\n manifest,\n studio,\n state,\n}: {\n manifest: ComponentManifest\n studio: StudioRegistry\n state: PreviewState\n}) {\n const ctx = useMemo(() => previewContext(studio), [studio])\n const serverOnly = manifest.clientRenderable === false\n const status = componentStatus(studio, manifest)\n const displayName = manifest.title ?? manifest.id\n\n // EC-330: the same config-sourced breakpoint set the builder canvas toolbar\n // offers (`canvas-breakpoints.ts`) — reused, not redefined, so a preview and\n // the real canvas never disagree about the site's responsive widths.\n // Defaults to the always-present 'full' (responsive) option.\n const { viewports } = useCanvasViewports()\n const [viewport, setViewport] = useState(viewports[0]!.key)\n\n return (\n <div className=\"flex h-full min-h-0 flex-col\">\n <Row gap=\"1\" wrap align=\"center\" className=\"shrink-0 border-b border-border px-3 py-2\">\n {state.specs.length > 1 ? (\n <Row\n gap=\"1\"\n wrap\n role=\"group\"\n aria-label={translate('components.fixtureRunner.statesAria')}\n >\n {state.specs.map((spec, i) => (\n <TabButton key={spec.name} active={i === state.index} onClick={() => state.setIndex(i)}>\n {spec.name}\n </TabButton>\n ))}\n </Row>\n ) : null}\n <Spacer />\n <Row\n gap=\"1\"\n wrap\n role=\"group\"\n aria-label={translate('components.preview.breakpointAria')}\n >\n {viewports.map((option) => (\n <PreviewBreakpointButton\n key={option.key}\n option={option}\n active={option.key === viewport}\n onSelect={() => setViewport(option.key)}\n />\n ))}\n </Row>\n {state.dirty ? (\n <Button variant=\"ghost\" size=\"sm\" onClick={state.resetAll} data-testid=\"preview-reset\">\n <RotateCcw /> {translate('components.preview.reset')}\n </Button>\n ) : null}\n </Row>\n\n <div\n className=\"canvas-grid min-h-0 flex-1 overflow-auto p-6\"\n data-fixture-state={state.specs[state.index]?.name}\n >\n {serverOnly ? (\n <ServerOnlyNotice />\n ) : (\n <ComponentPreviewFrame\n node={state.node}\n ctx={ctx}\n displayName={displayName}\n width={viewportWidth(viewports, viewport)}\n />\n )}\n {status === 'incompatible' && !serverOnly ? (\n <Text size=\"xs\" tone=\"muted\" className=\"mx-auto mt-3 max-w-2xl\">\n {translate('components.preview.incompatibleNote')}\n </Text>\n ) : null}\n </div>\n </div>\n )\n}\n\n/**\n * One breakpoint option in the preview's width switcher. Mirrors the builder\n * canvas toolbar's `ViewportButton` (`composition-field-editor.tsx`) — same\n * `Button`/active-state styling — but drives LOCAL preview state instead of\n * the builder store (this surface has no composition/undo stack).\n *\n * EC-328: evaluated against the shared `TabButton`/`SegmentedControl`\n * primitives and kept separate — it's built on the shared `Button` (not a\n * bare hand-rolled `<button>`, so it wasn't part of the duplication those\n * primitives address), and carries an interpolated `aria-label` plus a\n * conditional px-value `title` tooltip neither primitive's terse API models.\n */\nfunction PreviewBreakpointButton({\n option,\n active,\n onSelect,\n}: {\n option: ViewportOption\n active: boolean\n onSelect: () => void\n}) {\n return (\n <Button\n size=\"sm\"\n variant=\"ghost\"\n aria-label={translate('builder.canvas.viewportPreviewAria', { label: option.label })}\n aria-pressed={active}\n title={\n option.px !== undefined\n ? `${option.label} · ${option.px}px`\n : translate('builder.canvas.viewportWidthTitle', { label: option.label })\n }\n onClick={onSelect}\n className={cn('px-2 text-xs', active && 'bg-accent text-accent-foreground')}\n >\n {option.label}\n </Button>\n )\n}\n\nfunction ServerOnlyNotice() {\n return (\n <div className=\"mx-auto grid max-w-2xl place-items-center rounded-lg border border-dashed border-border bg-muted/30 p-8 text-center\">\n <Stack gap=\"2\" align=\"center\">\n <MonitorOff className=\"size-5 text-muted-foreground\" aria-hidden />\n <Text size=\"sm\" weight=\"medium\">\n {translate('components.preview.serverOnlyTitle')}\n </Text>\n <Text size=\"xs\" tone=\"muted\" className=\"max-w-sm\">\n {translate('components.preview.serverOnlyBody')}\n </Text>\n </Stack>\n </div>\n )\n}\n\n/** Floor for the auto-height iframe — never collapses to a sliver while empty/loading. */\nconst MIN_PREVIEW_HEIGHT = 360\n\n/**\n * The live preview render surface. Reuses the BuilderCanvas styling mechanism\n * (EC-061, `canvas.tsx`): the component renders inside an ISOLATED same-origin\n * iframe that `<link>`s the project's canvas stylesheet\n * (`getCanvasStylesheetUrl()` — the consuming app's delivery CSS + studio CSS), so\n * a component built with the site's Tailwind theme previews with the site's styles,\n * exactly as it does on the canvas and in delivery. Using the iframe (not the\n * studio DOM) is what keeps the delivery CSS scoped and off the studio chrome.\n *\n * Unlike the builder canvas, this iframe's document is deliberately left OUT of\n * the studio's own dark/light class: this is a standalone-component reference\n * surface (not a full page), so its own negative space around the component must\n * read as a light, site-like backdrop — never the studio chrome's current theme\n * (a black frame is exactly what leaks through when the studio is dark-themed and\n * the iframe root inherits that class). The canvas stylesheet's `:root` (light)\n * tokens supply that backdrop for free once the `.dark` class is never added here.\n *\n * Sizing: width is driven by the caller (the breakpoint selector); height is\n * measured live from the rendered content via `ResizeObserver` (EC-330) so a\n * preset switch or a prop edit — both of which change what's portaled into\n * `doc.body` — always show without clipping or dead space.\n *\n * The render is wrapped in {@link PreviewErrorBoundary} so a component that throws\n * shows the EC-191 fallback instead of taking the whole Components view down.\n */\nfunction ComponentPreviewFrame({\n node,\n ctx,\n displayName,\n width,\n}: {\n node: ComponentNode\n ctx: RenderContext\n displayName: string\n /** CSS width for the iframe — '100%' (responsive) or a fixed breakpoint px width. */\n width: string\n}) {\n const iframeRef = useRef<HTMLIFrameElement>(null)\n const [doc, setDoc] = useState<Document | null>(null)\n const [height, setHeight] = useState(MIN_PREVIEW_HEIGHT)\n\n const wireUp = useCallback(() => {\n const d = iframeRef.current?.contentDocument\n if (!d || !d.body) return\n // Deliberately no `.dark` here (see the surface note above) — the light\n // `:root` tokens from the injected stylesheet are the intended backdrop.\n // Unset stylesheet (tests / an app that never called\n // `setCanvasStylesheetUrl`) → skip the link.\n const appCss = getCanvasStylesheetUrl()\n if (appCss && !d.getElementById('ec-app-css')) {\n const link = d.createElement('link')\n link.id = 'ec-app-css'\n link.rel = 'stylesheet'\n link.href = appCss\n d.head.appendChild(link)\n }\n d.body.className = 'bg-background text-foreground font-sans'\n d.body.style.margin = '0'\n d.body.style.padding = '24px'\n setDoc(d)\n }, [])\n\n // Handle the already-loaded case (srcDoc can load before onLoad attaches).\n useEffect(() => {\n if (iframeRef.current?.contentDocument?.readyState === 'complete') wireUp()\n }, [wireUp])\n\n // Auto-height (EC-330): a same-origin iframe exposes its own document, so a\n // `ResizeObserver` on the BODY tracks its live (height: auto) content size —\n // re-firing on its own whenever the portaled render changes (preset switch,\n // prop edit), no manual re-measure wiring needed. Attached per `doc` (re-runs\n // whenever the iframe reloads), not just on mount. Loop-safety: the observed\n // element (the iframe's body) is never the element this effect resizes (the\n // IFRAME itself) — writing height never feeds back into the observed box, and\n // width is never derived from height, so there is no growth loop. Guarded for\n // environments without ResizeObserver (jsdom/tests, older embeds).\n useEffect(() => {\n const body = doc?.body\n if (!body || typeof ResizeObserver === 'undefined') return\n const measure = () => setHeight(Math.max(body.scrollHeight, MIN_PREVIEW_HEIGHT))\n measure()\n const observer = new ResizeObserver(measure)\n observer.observe(body)\n return () => observer.disconnect()\n }, [doc])\n\n return (\n <>\n <iframe\n ref={iframeRef}\n onLoad={wireUp}\n title={translate('components.detail.tab.preview')}\n style={{ width, height, maxWidth: '100%' }}\n className=\"mx-auto block rounded-lg border border-border bg-background shadow-sm\"\n srcDoc=\"<!doctype html><html><head></head><body></body></html>\"\n />\n {doc\n ? createPortal(\n <PreviewErrorBoundary displayName={displayName} resetKey={node}>\n <PreviewLiveRender node={node} ctx={ctx} />\n </PreviewErrorBoundary>,\n doc.body,\n )\n : null}\n </>\n )\n}\n\n/** Renders the node through the runtime renderer, INSIDE a component render so the\n * error boundary catches synchronous render throws (mirrors the blocks-panel\n * thumbnail's `LiveRender`). */\nfunction PreviewLiveRender({ node, ctx }: { node: ComponentNode; ctx: RenderContext }) {\n return <>{renderNode(node, ctx)}</>\n}\n\ninterface PreviewBoundaryState {\n error: Error | null\n}\n\n/**\n * EC-191 resilience for the Components view: a component whose render throws — a\n * missing provider/context (e.g. a prop control that needs a document's\n * `CollectionViewSource`), a runtime bug — shows the documented \"preview\n * unavailable\" fallback ({@link PreviewUnavailable}) instead of taking the whole\n * view down. It resets when the previewed `resetKey` (the node) changes, so\n * switching the fixture state or editing a prop retries the render.\n */\nexport class PreviewErrorBoundary extends Component<\n { children: ReactNode; displayName: string; resetKey: unknown },\n PreviewBoundaryState\n> {\n override state: PreviewBoundaryState = { error: null }\n\n static getDerivedStateFromError(error: Error): PreviewBoundaryState {\n return { error }\n }\n\n override componentDidUpdate(prev: Readonly<{ resetKey: unknown }>) {\n if (this.state.error && prev.resetKey !== this.props.resetKey) {\n this.setState({ error: null })\n }\n }\n\n override render(): ReactNode {\n if (this.state.error) {\n return <PreviewUnavailable displayName={this.props.displayName} error={this.state.error} />\n }\n return this.props.children\n }\n}\n\n/**\n * The EC-191 fallback panel — component name + \"preview unavailable\" + the error.\n * Rendered INTO the preview iframe (which carries only the project stylesheet, and\n * may carry none in tests), so it uses inline styles rather than studio UI classes\n * — matching the canvas's own in-iframe placeholder convention.\n */\nexport function PreviewUnavailable({ displayName, error }: { displayName: string; error: Error }) {\n return (\n <div\n data-preview-unavailable\n style={{\n boxSizing: 'border-box',\n maxWidth: '42rem',\n margin: '0 auto',\n border: '1px dashed rgba(120,120,120,0.5)',\n borderRadius: 8,\n padding: '24px 28px',\n background: 'rgba(127,127,127,0.06)',\n color: 'rgba(90,90,90,0.95)',\n font: '14px/1.5 system-ui, -apple-system, sans-serif',\n textAlign: 'center',\n }}\n >\n <div style={{ fontWeight: 600 }}>⚠ {translate('components.preview.unavailableTitle')}</div>\n <div style={{ marginTop: 4, fontWeight: 600, opacity: 0.9 }}>{displayName}</div>\n <div style={{ marginTop: 6, fontSize: 13, opacity: 0.85, wordBreak: 'break-word' }}>\n {error.message}\n </div>\n </div>\n )\n}\n\n/**\n * The editable Props pane (right inspector). Every non-`blocks` prop is edited\n * through the shared {@link PropValueControl} — the exact control set documents\n * use (EC-190/EC-314 phase 4) — so a change re-renders the preview immediately.\n * `blocks` props are a canvas (composition) concern, edited in a document, not here.\n */\nexport function PropsEditorPane({\n manifest,\n state,\n}: {\n manifest: ComponentManifest\n state: PreviewState\n}) {\n const editable = Object.entries(manifest.props).filter(([, spec]) => spec.type !== 'blocks')\n const fixture = state.specs[state.index]?.node\n if (editable.length === 0) {\n return (\n <Text size=\"sm\" tone=\"subtle\" className=\"p-4\">\n {translate('components.fieldInspector.noProps')}\n </Text>\n )\n }\n return (\n <Stack gap=\"4\" className=\"p-4\">\n {editable.map(([name, spec]) => {\n const id = `prop-${name}`\n const overridden = state.overrides[name] !== undefined\n return (\n <Field\n key={name}\n label={\n <Row gap=\"2\">\n <span>{localizedLabel((spec as PropField).form?.label, name)}</span>\n {overridden ? <Badge variant=\"info\">{translate('components.preview.edited')}</Badge> : null}\n </Row>\n }\n htmlFor={id}\n hint={localizedLabel((spec as PropField).form?.description) || undefined}\n >\n <PropValueControl\n id={id}\n name={name}\n spec={spec as PropField}\n value={\n overridden\n ? staticProp(state.overrides[name]!)\n : (fixture?.props?.[name] ?? undefined)\n }\n onSet={(v) => state.setOverride(name, v)}\n onClear={() => state.clearOverride(name)}\n />\n </Field>\n )\n })}\n {state.dirty ? (\n <Button variant=\"outline\" size=\"sm\" onClick={state.resetAll} className=\"self-start\">\n <RotateCcw /> {translate('components.preview.resetProps')}\n </Button>\n ) : null}\n </Stack>\n )\n}\n\n/**\n * The Slots pane (right inspector): the component's declared child regions and,\n * for a fixture that supplies slot content, a note that the preview's slot content\n * follows the selected state. Documents the pragmatic scope call — no slot-tree\n * editing on this reference surface.\n */\nexport function SlotsInfoPane({ manifest }: { manifest: ComponentManifest }) {\n if (manifest.slots.length === 0) {\n return (\n <Text size=\"sm\" tone=\"subtle\" className=\"p-4\">\n {translate('components.fieldInspector.noSlots')}\n </Text>\n )\n }\n return (\n <Stack gap=\"3\" className=\"p-4\">\n <Text size=\"xs\" tone=\"muted\">\n {translate('components.preview.slotsNote')}\n </Text>\n <div className=\"divide-y divide-border rounded-md border border-border\">\n {manifest.slots.map((slot) => (\n <div key={slot.name} className=\"flex flex-col gap-1 p-3\">\n <Row gap=\"2\">\n <Code tone=\"primary\">{slot.name}</Code>\n {slot.required ? (\n <Badge variant=\"warning\">{translate('common.required')}</Badge>\n ) : (\n <Badge variant=\"outline\">{translate('common.optional')}</Badge>\n )}\n </Row>\n {slot.allow && slot.allow.length > 0 ? (\n <Row gap=\"2\" className=\"text-xs\" wrap>\n <Text size=\"xs\" tone=\"subtle\">\n {translate('components.fieldInspector.allows')}\n </Text>\n {slot.allow.map((id) => (\n <Code key={id} tone=\"muted\">\n {id}\n </Code>\n ))}\n </Row>\n ) : null}\n </div>\n ))}\n </div>\n </Stack>\n )\n}\n"]}
1
+ {"version":3,"file":"component-preview.js","sourceRoot":"","sources":["../../../src/components/components/component-preview.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Component, useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { ReactNode } from 'react'\nimport { createPortal } from 'react-dom'\nimport { MonitorOff, RotateCcw } from 'lucide-react'\nimport { renderNode } from '@elytracms/core/runtime-renderer'\nimport type { RenderContext } from '@elytracms/core/runtime-renderer'\nimport { staticProp } from '@elytracms/core/project-graph'\nimport type { ComponentNode, JsonValue } from '@elytracms/core/project-graph'\nimport type { ComponentManifest, PropField } from '@elytracms/core/component-registry'\nimport { componentStatus, previewContext } from '@elytracms/studio/lib/registry'\nimport type { StudioRegistry } from '@elytracms/studio/lib/registry'\nimport { previewSpecs } from '@elytracms/studio/lib/registry/preview'\nimport type { PreviewSpec } from '@elytracms/studio/lib/registry/preview'\nimport { Badge, Button, Code, Field, Row, Spacer, Stack, TabButton, Text } from '@elytracms/studio/ui'\nimport { localizedLabel, translate } from '@elytracms/studio/lib/i18n'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { resolveDeploymentCanvasTheme } from '@elytracms/studio/lib/workspace'\nimport { wireCanvasChrome } from '../builder/canvas-chrome'\nimport { getCanvasStylesheetUrl } from '../builder/canvas-stylesheet'\nimport { useCanvasViewports, viewportWidth } from '../builder/canvas-breakpoints'\nimport type { ViewportOption } from '../builder/canvas-breakpoints'\nimport { PropValueControl } from '../cms/prop-fields'\n\n/**\n * EC-320 — the editable component preview. A component's declared preview states\n * (fixtures) select the SAMPLE STATE (slot content, base props); on top of that\n * the user edits individual prop values in the Props sidebar and the preview\n * re-renders live through the SAME runtime-renderer path the Builder and export\n * use (EC-054). Slots follow the selected fixture — full slot-tree editing is out\n * of scope for this reference surface (that's the composition editor's job); the\n * Slots pane documents what a component accepts and which state supplies content.\n */\n\nexport interface PreviewState {\n specs: PreviewSpec[]\n index: number\n setIndex: (i: number) => void\n /** Per-prop static-value overrides applied over the selected fixture. */\n overrides: Record<string, JsonValue>\n setOverride: (name: string, value: JsonValue) => void\n clearOverride: (name: string) => void\n resetAll: () => void\n dirty: boolean\n /** The live node: the selected fixture with prop overrides applied. */\n node: ComponentNode\n}\n\n/** Preview state for a manifest: the fixture selection + the live prop overrides. */\nexport function usePreviewState(manifest: ComponentManifest): PreviewState {\n const specs = useMemo(() => previewSpecs(manifest), [manifest])\n const [index, setIndexRaw] = useState(0)\n const [overrides, setOverrides] = useState<Record<string, JsonValue>>({})\n\n // Switching preview state resets prop edits — they were relative to the old state.\n const setIndex = (i: number) => {\n setIndexRaw(i)\n setOverrides({})\n }\n const setOverride = (name: string, value: JsonValue) =>\n setOverrides((o) => ({ ...o, [name]: value }))\n const clearOverride = (name: string) =>\n setOverrides((o) => {\n const next = { ...o }\n delete next[name]\n return next\n })\n const resetAll = () => setOverrides({})\n\n const base = specs[Math.min(index, specs.length - 1)]?.node\n const node = useMemo<ComponentNode>(() => {\n const fixture = base ?? { id: `preview-${manifest.id}`, componentId: manifest.id, props: {} }\n const props = { ...(fixture.props ?? {}) }\n for (const [name, value] of Object.entries(overrides)) props[name] = staticProp(value)\n return { ...fixture, props }\n }, [base, overrides, manifest.id])\n\n return {\n specs,\n index: Math.min(index, Math.max(specs.length - 1, 0)),\n setIndex,\n overrides,\n setOverride,\n clearOverride,\n resetAll,\n dirty: Object.keys(overrides).length > 0,\n node,\n }\n}\n\n/** Re-id a preview node into the canvas `node-<n>` namespace for embedding (transfer). */\nexport function embedNodeFrom(node: ComponentNode, id: string): ComponentNode {\n return { ...node, id }\n}\n\n/**\n * The live preview surface: the fixture-state selector (when a component declares\n * more than one) plus the rendered node. Server-only components (EC-191\n * `clientRenderable: false`) can't run on the client-rendered canvas, so they show\n * a documented fallback rather than risk a crash; a missing implementation falls\n * back through the renderer itself (the incompatible state).\n */\nexport function ComponentPreview({\n manifest,\n studio,\n state,\n}: {\n manifest: ComponentManifest\n studio: StudioRegistry\n state: PreviewState\n}) {\n const ctx = useMemo(() => previewContext(studio), [studio])\n const serverOnly = manifest.clientRenderable === false\n const status = componentStatus(studio, manifest)\n const displayName = localizedLabel(manifest.title, manifest.id)\n\n // EC-330: the same config-sourced breakpoint set the builder canvas toolbar\n // offers (`canvas-breakpoints.ts`) — reused, not redefined, so a preview and\n // the real canvas never disagree about the site's responsive widths.\n // Defaults to the always-present 'full' (responsive) option.\n const { viewports } = useCanvasViewports()\n const [viewport, setViewport] = useState(viewports[0]!.key)\n\n return (\n <div className=\"flex h-full min-h-0 flex-col\">\n <Row gap=\"1\" wrap align=\"center\" className=\"shrink-0 border-b border-border px-3 py-2\">\n {state.specs.length > 1 ? (\n <Row\n gap=\"1\"\n wrap\n role=\"group\"\n aria-label={translate('components.fixtureRunner.statesAria')}\n >\n {state.specs.map((spec, i) => (\n <TabButton key={spec.name} active={i === state.index} onClick={() => state.setIndex(i)}>\n {spec.name}\n </TabButton>\n ))}\n </Row>\n ) : null}\n <Spacer />\n <Row\n gap=\"1\"\n wrap\n role=\"group\"\n aria-label={translate('components.preview.breakpointAria')}\n >\n {viewports.map((option) => (\n <PreviewBreakpointButton\n key={option.key}\n option={option}\n active={option.key === viewport}\n onSelect={() => setViewport(option.key)}\n />\n ))}\n </Row>\n {state.dirty ? (\n <Button variant=\"ghost\" size=\"sm\" onClick={state.resetAll} data-testid=\"preview-reset\">\n <RotateCcw /> {translate('components.preview.reset')}\n </Button>\n ) : null}\n </Row>\n\n <div\n className=\"canvas-grid min-h-0 flex-1 overflow-auto p-6\"\n data-fixture-state={state.specs[state.index]?.name}\n >\n {serverOnly ? (\n <ServerOnlyNotice />\n ) : (\n <ComponentPreviewFrame\n node={state.node}\n ctx={ctx}\n displayName={displayName}\n width={viewportWidth(viewports, viewport)}\n />\n )}\n {status === 'incompatible' && !serverOnly ? (\n <Text size=\"xs\" tone=\"muted\" className=\"mx-auto mt-3 max-w-2xl\">\n {translate('components.preview.incompatibleNote')}\n </Text>\n ) : null}\n </div>\n </div>\n )\n}\n\n/**\n * One breakpoint option in the preview's width switcher. Mirrors the builder\n * canvas toolbar's `ViewportButton` (`composition-field-editor.tsx`) — same\n * `Button`/active-state styling — but drives LOCAL preview state instead of\n * the builder store (this surface has no composition/undo stack).\n *\n * EC-328: evaluated against the shared `TabButton`/`SegmentedControl`\n * primitives and kept separate — it's built on the shared `Button` (not a\n * bare hand-rolled `<button>`, so it wasn't part of the duplication those\n * primitives address), and carries an interpolated `aria-label` plus a\n * conditional px-value `title` tooltip neither primitive's terse API models.\n */\nfunction PreviewBreakpointButton({\n option,\n active,\n onSelect,\n}: {\n option: ViewportOption\n active: boolean\n onSelect: () => void\n}) {\n return (\n <Button\n size=\"sm\"\n variant=\"ghost\"\n aria-label={translate('builder.canvas.viewportPreviewAria', { label: option.label })}\n aria-pressed={active}\n title={\n option.px !== undefined\n ? `${option.label} · ${option.px}px`\n : translate('builder.canvas.viewportWidthTitle', { label: option.label })\n }\n onClick={onSelect}\n className={cn('px-2 text-xs', active && 'bg-accent text-accent-foreground')}\n >\n {option.label}\n </Button>\n )\n}\n\nfunction ServerOnlyNotice() {\n return (\n <div className=\"mx-auto grid max-w-2xl place-items-center rounded-lg border border-dashed border-border bg-muted/30 p-8 text-center\">\n <Stack gap=\"2\" align=\"center\">\n <MonitorOff className=\"size-5 text-muted-foreground\" aria-hidden />\n <Text size=\"sm\" weight=\"medium\">\n {translate('components.preview.serverOnlyTitle')}\n </Text>\n <Text size=\"xs\" tone=\"muted\" className=\"max-w-sm\">\n {translate('components.preview.serverOnlyBody')}\n </Text>\n </Stack>\n </div>\n )\n}\n\n/** Floor for the auto-height iframe — never collapses to a sliver while empty/loading. */\nconst MIN_PREVIEW_HEIGHT = 360\n\n/**\n * The live preview render surface. Reuses the BuilderCanvas styling mechanism\n * (EC-061, `canvas.tsx`) — since EC-414 through the SAME code path, `wireCanvasChrome`\n * (closing the EC-389 follow-up): the component renders inside an ISOLATED\n * same-origin iframe that `<link>`s the project's canvas stylesheet\n * (`getCanvasStylesheetUrl()` — the consumer's theme entry; in the legacy merged\n * world also the studio CSS), so a component built with the site's Tailwind theme\n * previews with the site's styles, exactly as it does on the canvas and in\n * delivery. Using the iframe (not the studio DOM) is what keeps the delivery CSS\n * scoped and off the studio chrome.\n *\n * Unlike the builder canvas, this iframe's document is deliberately left OUT of\n * the studio's own dark/light class: this is a standalone-component reference\n * surface (not a full page), so its own negative space around the component must\n * read as a light, site-like backdrop — never the studio chrome's current theme\n * (a black frame is exactly what leaks through when the studio is dark-themed and\n * the iframe root inherits that class). The chrome's world probe supplies that\n * backdrop: the neutral backdrop rules in the new world, the studio `:root`\n * (light) tokens in the legacy one.\n *\n * Sizing: width is driven by the caller (the breakpoint selector); height is\n * measured live from the rendered content via `ResizeObserver` (EC-330) so a\n * preset switch or a prop edit — both of which change what's portaled into\n * `doc.body` — always show without clipping or dead space.\n *\n * The render is wrapped in {@link PreviewErrorBoundary} so a component that throws\n * shows the EC-191 fallback instead of taking the whole Components view down.\n */\nfunction ComponentPreviewFrame({\n node,\n ctx,\n displayName,\n width,\n}: {\n node: ComponentNode\n ctx: RenderContext\n displayName: string\n /** CSS width for the iframe — '100%' (responsive) or a fixed breakpoint px width. */\n width: string\n}) {\n const iframeRef = useRef<HTMLIFrameElement>(null)\n const [doc, setDoc] = useState<Document | null>(null)\n const [height, setHeight] = useState(MIN_PREVIEW_HEIGHT)\n\n const wireUp = useCallback(() => {\n const d = iframeRef.current?.contentDocument\n if (!d || !d.body) return\n // ONE code path with the builder canvas (EC-414 AD-B item 4): stylesheet\n // link + chrome css + consumer canvas theme + the world probe. No kit\n // tokens here — this is a registry-level reference surface, not a project\n // page. The dev theme notice is the builder canvas's job, not this pane's.\n wireCanvasChrome(d, {\n stylesheetUrl: getCanvasStylesheetUrl(),\n theme: resolveDeploymentCanvasTheme(),\n })\n setDoc(d)\n }, [])\n\n // Handle the already-loaded case (srcDoc can load before onLoad attaches).\n useEffect(() => {\n if (iframeRef.current?.contentDocument?.readyState === 'complete') wireUp()\n }, [wireUp])\n\n // Auto-height (EC-330): a same-origin iframe exposes its own document, so a\n // `ResizeObserver` on the BODY tracks its live (height: auto) content size —\n // re-firing on its own whenever the portaled render changes (preset switch,\n // prop edit), no manual re-measure wiring needed. Attached per `doc` (re-runs\n // whenever the iframe reloads), not just on mount. Loop-safety: the observed\n // element (the iframe's body) is never the element this effect resizes (the\n // IFRAME itself) — writing height never feeds back into the observed box, and\n // width is never derived from height, so there is no growth loop. Guarded for\n // environments without ResizeObserver (jsdom/tests, older embeds).\n useEffect(() => {\n const body = doc?.body\n if (!body || typeof ResizeObserver === 'undefined') return\n const measure = () => setHeight(Math.max(body.scrollHeight, MIN_PREVIEW_HEIGHT))\n measure()\n const observer = new ResizeObserver(measure)\n observer.observe(body)\n return () => observer.disconnect()\n }, [doc])\n\n return (\n <>\n <iframe\n ref={iframeRef}\n onLoad={wireUp}\n title={translate('components.detail.tab.preview')}\n style={{ width, height, maxWidth: '100%' }}\n className=\"mx-auto block rounded-lg border border-border bg-background shadow-sm\"\n srcDoc=\"<!doctype html><html><head></head><body></body></html>\"\n />\n {doc\n ? createPortal(\n <PreviewErrorBoundary displayName={displayName} resetKey={node}>\n <PreviewLiveRender node={node} ctx={ctx} />\n </PreviewErrorBoundary>,\n doc.body,\n )\n : null}\n </>\n )\n}\n\n/** Renders the node through the runtime renderer, INSIDE a component render so the\n * error boundary catches synchronous render throws (mirrors the blocks-panel\n * thumbnail's `LiveRender`). */\nfunction PreviewLiveRender({ node, ctx }: { node: ComponentNode; ctx: RenderContext }) {\n return <>{renderNode(node, ctx)}</>\n}\n\ninterface PreviewBoundaryState {\n error: Error | null\n}\n\n/**\n * EC-191 resilience for the Components view: a component whose render throws — a\n * missing provider/context (e.g. a prop control that needs a document's\n * `CollectionViewSource`), a runtime bug — shows the documented \"preview\n * unavailable\" fallback ({@link PreviewUnavailable}) instead of taking the whole\n * view down. It resets when the previewed `resetKey` (the node) changes, so\n * switching the fixture state or editing a prop retries the render.\n */\nexport class PreviewErrorBoundary extends Component<\n { children: ReactNode; displayName: string; resetKey: unknown },\n PreviewBoundaryState\n> {\n override state: PreviewBoundaryState = { error: null }\n\n static getDerivedStateFromError(error: Error): PreviewBoundaryState {\n return { error }\n }\n\n override componentDidUpdate(prev: Readonly<{ resetKey: unknown }>) {\n if (this.state.error && prev.resetKey !== this.props.resetKey) {\n this.setState({ error: null })\n }\n }\n\n override render(): ReactNode {\n if (this.state.error) {\n return <PreviewUnavailable displayName={this.props.displayName} error={this.state.error} />\n }\n return this.props.children\n }\n}\n\n/**\n * The EC-191 fallback panel — component name + \"preview unavailable\" + the error.\n * Rendered INTO the preview iframe (which carries only the project stylesheet, and\n * may carry none in tests), so it uses inline styles rather than studio UI classes\n * — the EC-414 AD-B chrome contract, with the `.ec-chrome` containment recipe on\n * its root (walked by the chrome contract test).\n */\nexport function PreviewUnavailable({ displayName, error }: { displayName: string; error: Error }) {\n return (\n <div\n data-preview-unavailable\n className=\"ec-chrome\"\n style={{\n boxSizing: 'border-box',\n maxWidth: '42rem',\n margin: '0 auto',\n border: '1px dashed rgba(120,120,120,0.5)',\n borderRadius: 8,\n padding: '24px 28px',\n background: 'rgba(127,127,127,0.06)',\n color: 'rgba(90,90,90,0.95)',\n font: '14px/1.5 system-ui, -apple-system, sans-serif',\n textAlign: 'center',\n }}\n >\n <div style={{ fontWeight: 600 }}>⚠ {translate('components.preview.unavailableTitle')}</div>\n <div style={{ marginTop: 4, fontWeight: 600, opacity: 0.9 }}>{displayName}</div>\n <div style={{ marginTop: 6, fontSize: 13, opacity: 0.85, wordBreak: 'break-word' }}>\n {error.message}\n </div>\n </div>\n )\n}\n\n/**\n * The editable Props pane (right inspector). Every non-`blocks` prop is edited\n * through the shared {@link PropValueControl} — the exact control set documents\n * use (EC-190/EC-314 phase 4) — so a change re-renders the preview immediately.\n * `blocks` props are a canvas (composition) concern, edited in a document, not here.\n */\nexport function PropsEditorPane({\n manifest,\n state,\n}: {\n manifest: ComponentManifest\n state: PreviewState\n}) {\n const editable = Object.entries(manifest.props).filter(([, spec]) => spec.type !== 'blocks')\n const fixture = state.specs[state.index]?.node\n if (editable.length === 0) {\n return (\n <Text size=\"sm\" tone=\"subtle\" className=\"p-4\">\n {translate('components.fieldInspector.noProps')}\n </Text>\n )\n }\n return (\n <Stack gap=\"4\" className=\"p-4\">\n {editable.map(([name, spec]) => {\n const id = `prop-${name}`\n const overridden = state.overrides[name] !== undefined\n return (\n <Field\n key={name}\n label={\n <Row gap=\"2\">\n <span>{localizedLabel((spec as PropField).form?.label, name)}</span>\n {overridden ? <Badge variant=\"info\">{translate('components.preview.edited')}</Badge> : null}\n </Row>\n }\n htmlFor={id}\n hint={localizedLabel((spec as PropField).form?.description) || undefined}\n >\n <PropValueControl\n id={id}\n name={name}\n spec={spec as PropField}\n value={\n overridden\n ? staticProp(state.overrides[name]!)\n : (fixture?.props?.[name] ?? undefined)\n }\n onSet={(v) => state.setOverride(name, v)}\n onClear={() => state.clearOverride(name)}\n />\n </Field>\n )\n })}\n {state.dirty ? (\n <Button variant=\"outline\" size=\"sm\" onClick={state.resetAll} className=\"self-start\">\n <RotateCcw /> {translate('components.preview.resetProps')}\n </Button>\n ) : null}\n </Stack>\n )\n}\n\n/**\n * The Slots pane (right inspector): the component's declared child regions and,\n * for a fixture that supplies slot content, a note that the preview's slot content\n * follows the selected state. Documents the pragmatic scope call — no slot-tree\n * editing on this reference surface.\n */\nexport function SlotsInfoPane({ manifest }: { manifest: ComponentManifest }) {\n if (manifest.slots.length === 0) {\n return (\n <Text size=\"sm\" tone=\"subtle\" className=\"p-4\">\n {translate('components.fieldInspector.noSlots')}\n </Text>\n )\n }\n return (\n <Stack gap=\"3\" className=\"p-4\">\n <Text size=\"xs\" tone=\"muted\">\n {translate('components.preview.slotsNote')}\n </Text>\n <div className=\"divide-y divide-border rounded-md border border-border\">\n {manifest.slots.map((slot) => (\n <div key={slot.name} className=\"flex flex-col gap-1 p-3\">\n <Row gap=\"2\">\n <Code tone=\"primary\">{slot.name}</Code>\n {slot.required ? (\n <Badge variant=\"warning\">{translate('common.required')}</Badge>\n ) : (\n <Badge variant=\"outline\">{translate('common.optional')}</Badge>\n )}\n </Row>\n {slot.allow && slot.allow.length > 0 ? (\n <Row gap=\"2\" className=\"text-xs\" wrap>\n <Text size=\"xs\" tone=\"subtle\">\n {translate('components.fieldInspector.allows')}\n </Text>\n {slot.allow.map((id) => (\n <Code key={id} tone=\"muted\">\n {id}\n </Code>\n ))}\n </Row>\n ) : null}\n </div>\n ))}\n </div>\n </Stack>\n )\n}\n"]}
@@ -3,7 +3,7 @@ import { Link, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router
3
3
  import { Search } from 'lucide-react';
4
4
  import { useMemo, useState } from 'react';
5
5
  import { componentStatus, getStudioRegistry } from '@elytracms/studio/lib/registry';
6
- import { translate } from '@elytracms/studio/lib/i18n';
6
+ import { localizedLabel, translate } from '@elytracms/studio/lib/i18n';
7
7
  import { Code, Input, Row, SegmentedControl, Spacer, Stack, Text } from '@elytracms/studio/ui';
8
8
  import { cn } from '@elytracms/studio/lib/utils';
9
9
  import { ComponentStatusDot } from './component-status.js';
@@ -57,6 +57,6 @@ function ComponentRow({ manifest, projectId, active, }) {
57
57
  const status = componentStatus(studio, manifest);
58
58
  return (_jsxs(Link, { to: STUDIO_PROJECT_ROUTE, params: { projectId, _splat: studioPath.component(manifest.id) }, "aria-current": active ? 'page' : undefined, className: cn('flex items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors', active
59
59
  ? 'bg-accent text-accent-foreground'
60
- : 'text-muted-foreground hover:bg-muted hover:text-foreground'), children: [_jsx(ComponentStatusDot, { status: status }), _jsx("span", { className: "min-w-0 flex-1 truncate font-medium text-foreground", children: manifest.title ?? manifest.id })] }));
60
+ : 'text-muted-foreground hover:bg-muted hover:text-foreground'), children: [_jsx(ComponentStatusDot, { status: status }), _jsx("span", { className: "min-w-0 flex-1 truncate font-medium text-foreground", children: localizedLabel(manifest.title, manifest.id) })] }));
61
61
  }
62
62
  //# sourceMappingURL=registry-browser.js.map