@elytracms/studio 0.0.67 → 0.0.69

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 (89) hide show
  1. package/dist/components/assets/asset-detail.d.ts +4 -2
  2. package/dist/components/assets/asset-detail.js +4 -2
  3. package/dist/components/assets/asset-detail.js.map +1 -1
  4. package/dist/components/assets/assets-collection-view-source.d.ts +30 -19
  5. package/dist/components/assets/assets-collection-view-source.js +55 -23
  6. package/dist/components/assets/assets-collection-view-source.js.map +1 -1
  7. package/dist/components/builder/canvas-chrome-css.js +6 -1
  8. package/dist/components/builder/canvas-chrome-css.js.map +1 -1
  9. package/dist/components/builder/property-inspector.d.ts +0 -21
  10. package/dist/components/builder/property-inspector.js +5 -22
  11. package/dist/components/builder/property-inspector.js.map +1 -1
  12. package/dist/components/builder/selection-overlay.d.ts +17 -4
  13. package/dist/components/builder/selection-overlay.js +17 -15
  14. package/dist/components/builder/selection-overlay.js.map +1 -1
  15. package/dist/components/builder/spacing-handles.d.ts +26 -1
  16. package/dist/components/builder/spacing-handles.js +66 -3
  17. package/dist/components/builder/spacing-handles.js.map +1 -1
  18. package/dist/components/cms/asset-picker-core.d.ts +52 -0
  19. package/dist/components/cms/asset-picker-core.js +69 -0
  20. package/dist/components/cms/asset-picker-core.js.map +1 -0
  21. package/dist/components/cms/asset-picker.d.ts +16 -4
  22. package/dist/components/cms/asset-picker.js +34 -50
  23. package/dist/components/cms/asset-picker.js.map +1 -1
  24. package/dist/components/cms/bulk-bar.d.ts +11 -1
  25. package/dist/components/cms/bulk-bar.js +10 -3
  26. package/dist/components/cms/bulk-bar.js.map +1 -1
  27. package/dist/components/cms/collection-table.js +19 -2
  28. package/dist/components/cms/collection-table.js.map +1 -1
  29. package/dist/components/cms/detail-editor.js +45 -54
  30. package/dist/components/cms/detail-editor.js.map +1 -1
  31. package/dist/components/cms/field-control.js +5 -1
  32. package/dist/components/cms/field-control.js.map +1 -1
  33. package/dist/components/cms/prop-fields.js +5 -1
  34. package/dist/components/cms/prop-fields.js.map +1 -1
  35. package/dist/components/cms/prop-visibility.d.ts +3 -0
  36. package/dist/components/cms/prop-visibility.js +31 -0
  37. package/dist/components/cms/prop-visibility.js.map +1 -0
  38. package/dist/components/cms/reference-confirm.js +5 -1
  39. package/dist/components/cms/reference-confirm.js.map +1 -1
  40. package/dist/components/cms/rich-text/component-embed.d.ts +8 -6
  41. package/dist/components/cms/rich-text/component-embed.js +21 -62
  42. package/dist/components/cms/rich-text/component-embed.js.map +1 -1
  43. package/dist/components/cms/rich-text/editor.d.ts +33 -4
  44. package/dist/components/cms/rich-text/editor.js +52 -22
  45. package/dist/components/cms/rich-text/editor.js.map +1 -1
  46. package/dist/components/cms/rich-text/embed-props.d.ts +60 -27
  47. package/dist/components/cms/rich-text/embed-props.js +102 -45
  48. package/dist/components/cms/rich-text/embed-props.js.map +1 -1
  49. package/dist/components/rail-view-source.d.ts +50 -1
  50. package/dist/components/rail-view-source.js +56 -2
  51. package/dist/components/rail-view-source.js.map +1 -1
  52. package/dist/components/redirects/redirects-collection-view-source.d.ts +3 -2
  53. package/dist/components/redirects/redirects-collection-view-source.js +4 -3
  54. package/dist/components/redirects/redirects-collection-view-source.js.map +1 -1
  55. package/dist/components/users/users-collection-view-source.js +1 -1
  56. package/dist/components/users/users-collection-view-source.js.map +1 -1
  57. package/dist/lib/collection-view/collection-view-source.d.ts +12 -0
  58. package/dist/lib/collection-view/collection-view-source.js.map +1 -1
  59. package/dist/lib/dnd/gap-drag.d.ts +8 -1
  60. package/dist/lib/dnd/gap-drag.js +4 -0
  61. package/dist/lib/dnd/gap-drag.js.map +1 -1
  62. package/dist/lib/i18n/messages.de.js +3 -2
  63. package/dist/lib/i18n/messages.de.js.map +1 -1
  64. package/dist/lib/i18n/messages.en.d.ts +1 -1
  65. package/dist/lib/i18n/messages.en.js +4 -2
  66. package/dist/lib/i18n/messages.en.js.map +1 -1
  67. package/dist/lib/references/references-store.d.ts +8 -1
  68. package/dist/lib/references/references-store.js +12 -2
  69. package/dist/lib/references/references-store.js.map +1 -1
  70. package/dist/ui/expandable-surface.d.ts +35 -25
  71. package/dist/ui/expandable-surface.js +41 -21
  72. package/dist/ui/expandable-surface.js.map +1 -1
  73. package/dist/ui/index.d.ts +1 -0
  74. package/dist/ui/index.js +1 -0
  75. package/dist/ui/index.js.map +1 -1
  76. package/dist/ui/surface-geometry.d.ts +71 -0
  77. package/dist/ui/surface-geometry.js +64 -0
  78. package/dist/ui/surface-geometry.js.map +1 -0
  79. package/package.json +2 -2
  80. package/src/styles/studio.css +30 -0
  81. package/dist/components/cms/rich-text/embed-inspector-context.d.ts +0 -50
  82. package/dist/components/cms/rich-text/embed-inspector-context.js +0 -12
  83. package/dist/components/cms/rich-text/embed-inspector-context.js.map +0 -1
  84. package/dist/components/cms/rich-text/embed-inspector.d.ts +0 -25
  85. package/dist/components/cms/rich-text/embed-inspector.js +0 -48
  86. package/dist/components/cms/rich-text/embed-inspector.js.map +0 -1
  87. package/dist/components/cms/use-embed-inspector-host.d.ts +0 -12
  88. package/dist/components/cms/use-embed-inspector-host.js +0 -17
  89. package/dist/components/cms/use-embed-inspector-host.js.map +0 -1
@@ -65,6 +65,36 @@
65
65
  --radius-xl: calc(var(--radius) + 4px);
66
66
  }
67
67
 
68
+ /*
69
+ * EC-431 — the centered stage surface (ExpandableSurface variant="stage") grows
70
+ * from center with a subtle scale/opacity entrance; the backdrop fades in. Both
71
+ * are consumed ONLY through `motion-safe:` variants, so `prefers-reduced-motion`
72
+ * gets an instant appearance (no transition at all).
73
+ */
74
+ @theme {
75
+ --animate-ec-stage-in: ec-stage-in 180ms cubic-bezier(0.22, 1, 0.36, 1);
76
+ --animate-ec-stage-fade: ec-stage-fade 180ms ease-out;
77
+
78
+ @keyframes ec-stage-in {
79
+ from {
80
+ opacity: 0;
81
+ transform: scale(0.97);
82
+ }
83
+ to {
84
+ opacity: 1;
85
+ transform: scale(1);
86
+ }
87
+ }
88
+ @keyframes ec-stage-fade {
89
+ from {
90
+ opacity: 0;
91
+ }
92
+ to {
93
+ opacity: 1;
94
+ }
95
+ }
96
+ }
97
+
68
98
  @layer base {
69
99
  * {
70
100
  border-color: var(--color-border);
@@ -1,50 +0,0 @@
1
- import type { ComponentNode } from '@elytracms/core/project-graph';
2
- import type { ComponentManifest } from '@elytracms/core/component-registry';
3
- /**
4
- * Selection-driven embed inspector plumbing (0.0.41) — a deliberately **TipTap-free**
5
- * seam between the rich-text editor and the CMS detail editor's right sidebar.
6
- *
7
- * When a `componentEmbed` node is selected inside a rich-text field, the field pushes
8
- * an {@link EmbedInspectorPayload} through this context; the detail editor swaps its
9
- * inspector sidebar for the embed's prop form (the same EC-190 controls the old modal
10
- * used). Deselecting clears it and the normal sidebar returns.
11
- *
12
- * It carries only plain data + callbacks (no `@tiptap/*` imports) so the detail
13
- * editor — which sits on the critical path and must NOT statically pull TipTap
14
- * (EC-322) — can consume it while the editor subtree stays behind `rich-text/lazy`.
15
- */
16
- export interface EmbedInspectorPayload {
17
- /**
18
- * Stable identity of the embedded node (its `ComponentNode.id`). Dedupes selection
19
- * races: when the selection moves from embed A to embed B, B's "open" and A's
20
- * "close" can interleave — clearing keys on this id so A never wipes B.
21
- */
22
- nodeId: string;
23
- /** The embedded component node whose props the inspector edits. */
24
- node: ComponentNode;
25
- /** Its manifest — drives which prop fields render. */
26
- manifest: ComponentManifest;
27
- /** Render the inspector read-only (mirrors the field's `readOnly`). */
28
- readOnly: boolean;
29
- /**
30
- * Commit an edited node. The field writes it back through one ProseMirror
31
- * `updateAttributes` transaction (undoable); the caller has already applied the
32
- * no-dirty guard, so this only fires on a real structural change.
33
- */
34
- onChange: (node: ComponentNode) => void;
35
- /** Move the editor selection off this node — the inspector's back affordance. */
36
- onDeselect: () => void;
37
- }
38
- export interface EmbedInspectorApi {
39
- /** Show (or refocus) the inspector for the currently-selected embed. */
40
- setActiveEmbed: (payload: EmbedInspectorPayload) => void;
41
- /** Hide the inspector, but only when `nodeId` is the one currently shown. */
42
- clearActiveEmbed: (nodeId: string) => void;
43
- }
44
- export declare const EmbedInspectorProvider: import("react").Provider<EmbedInspectorApi | null>;
45
- /**
46
- * The ambient embed-inspector sink, or `null` when the rich-text field is mounted
47
- * outside a host that provides one (the builder property inspector, the asset detail
48
- * pane). A `null` return is the signal to fall back to the modal prop editor.
49
- */
50
- export declare function useOptionalEmbedInspector(): EmbedInspectorApi | null;
@@ -1,12 +0,0 @@
1
- import { createContext, useContext } from 'react';
2
- const EmbedInspectorContext = createContext(null);
3
- export const EmbedInspectorProvider = EmbedInspectorContext.Provider;
4
- /**
5
- * The ambient embed-inspector sink, or `null` when the rich-text field is mounted
6
- * outside a host that provides one (the builder property inspector, the asset detail
7
- * pane). A `null` return is the signal to fall back to the modal prop editor.
8
- */
9
- export function useOptionalEmbedInspector() {
10
- return useContext(EmbedInspectorContext);
11
- }
12
- //# sourceMappingURL=embed-inspector-context.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"embed-inspector-context.js","sourceRoot":"","sources":["../../../../src/components/cms/rich-text/embed-inspector-context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AA+CjD,MAAM,qBAAqB,GAAG,aAAa,CAA2B,IAAI,CAAC,CAAA;AAE3E,MAAM,CAAC,MAAM,sBAAsB,GAAG,qBAAqB,CAAC,QAAQ,CAAA;AAEpE;;;;GAIG;AACH,MAAM,UAAU,yBAAyB;IACvC,OAAO,UAAU,CAAC,qBAAqB,CAAC,CAAA;AAC1C,CAAC","sourcesContent":["import { createContext, useContext } from 'react'\nimport type { ComponentNode } from '@elytracms/core/project-graph'\nimport type { ComponentManifest } from '@elytracms/core/component-registry'\n\n/**\n * Selection-driven embed inspector plumbing (0.0.41) — a deliberately **TipTap-free**\n * seam between the rich-text editor and the CMS detail editor's right sidebar.\n *\n * When a `componentEmbed` node is selected inside a rich-text field, the field pushes\n * an {@link EmbedInspectorPayload} through this context; the detail editor swaps its\n * inspector sidebar for the embed's prop form (the same EC-190 controls the old modal\n * used). Deselecting clears it and the normal sidebar returns.\n *\n * It carries only plain data + callbacks (no `@tiptap/*` imports) so the detail\n * editor — which sits on the critical path and must NOT statically pull TipTap\n * (EC-322) — can consume it while the editor subtree stays behind `rich-text/lazy`.\n */\nexport interface EmbedInspectorPayload {\n /**\n * Stable identity of the embedded node (its `ComponentNode.id`). Dedupes selection\n * races: when the selection moves from embed A to embed B, B's \"open\" and A's\n * \"close\" can interleave — clearing keys on this id so A never wipes B.\n */\n nodeId: string\n /** The embedded component node whose props the inspector edits. */\n node: ComponentNode\n /** Its manifest — drives which prop fields render. */\n manifest: ComponentManifest\n /** Render the inspector read-only (mirrors the field's `readOnly`). */\n readOnly: boolean\n /**\n * Commit an edited node. The field writes it back through one ProseMirror\n * `updateAttributes` transaction (undoable); the caller has already applied the\n * no-dirty guard, so this only fires on a real structural change.\n */\n onChange: (node: ComponentNode) => void\n /** Move the editor selection off this node — the inspector's back affordance. */\n onDeselect: () => void\n}\n\nexport interface EmbedInspectorApi {\n /** Show (or refocus) the inspector for the currently-selected embed. */\n setActiveEmbed: (payload: EmbedInspectorPayload) => void\n /** Hide the inspector, but only when `nodeId` is the one currently shown. */\n clearActiveEmbed: (nodeId: string) => void\n}\n\nconst EmbedInspectorContext = createContext<EmbedInspectorApi | null>(null)\n\nexport const EmbedInspectorProvider = EmbedInspectorContext.Provider\n\n/**\n * The ambient embed-inspector sink, or `null` when the rich-text field is mounted\n * outside a host that provides one (the builder property inspector, the asset detail\n * pane). A `null` return is the signal to fall back to the modal prop editor.\n */\nexport function useOptionalEmbedInspector(): EmbedInspectorApi | null {\n return useContext(EmbedInspectorContext)\n}\n"]}
@@ -1,25 +0,0 @@
1
- import type { EmbedInspectorPayload } from './embed-inspector-context.js';
2
- /**
3
- * The selection-driven embed prop inspector (0.0.41) — the detail editor's right
4
- * sidebar swaps to this when a `componentEmbed` node is selected in a rich-text
5
- * field. It replaces the retired-for-this-surface {@link EmbedPropsDialog} modal so
6
- * embed props are edited in the SAME place document fields are, not a third form
7
- * surface (the product-owner feedback that motivated the change).
8
- *
9
- * It reuses the exact modal machinery — the EC-190 {@link PropValueControl} stack and
10
- * the {@link editableEmbedProps}/{@link blocksEmbedProps} manifest partitioning — so
11
- * `blocks`-typed composition props are excluded (edited on the canvas) with a visible
12
- * note, and asset/relation/object props open their real pickers.
13
- *
14
- * Write-back is **immediate per prop change** (like the builder inspector): each edit
15
- * commits through the payload's `onChange` (one ProseMirror transaction upstream),
16
- * guarded by {@link resolveEmbedWrite} so an unchanged write never dirties the field.
17
- * There is no draft+Apply — the sidebar always reflects the committed node.
18
- *
19
- * TipTap-free by construction (see {@link EmbedInspectorPayload}) so the detail editor
20
- * can import it without pulling the editor runtime onto the critical path (EC-322).
21
- */
22
- export declare function EmbedInspector({ payload, className, }: {
23
- payload: EmbedInspectorPayload;
24
- className?: string;
25
- }): import("react").JSX.Element;
@@ -1,48 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { ChevronLeft } from 'lucide-react';
3
- import { Button, Field, Row, Separator, Stack, Text } from '@elytracms/studio/ui';
4
- import { localizedLabel, translate } from '@elytracms/studio/lib/i18n';
5
- import { componentDisplayName } from '@elytracms/studio/lib/persona/labels';
6
- import { cn } from '@elytracms/studio/lib/utils';
7
- import { PropValueControl } from '../prop-fields.js';
8
- import { blocksEmbedProps, clearComponentNodeProp, editableEmbedProps, resolveEmbedWrite, setComponentNodeProp, } from './embed-props.js';
9
- /**
10
- * The selection-driven embed prop inspector (0.0.41) — the detail editor's right
11
- * sidebar swaps to this when a `componentEmbed` node is selected in a rich-text
12
- * field. It replaces the retired-for-this-surface {@link EmbedPropsDialog} modal so
13
- * embed props are edited in the SAME place document fields are, not a third form
14
- * surface (the product-owner feedback that motivated the change).
15
- *
16
- * It reuses the exact modal machinery — the EC-190 {@link PropValueControl} stack and
17
- * the {@link editableEmbedProps}/{@link blocksEmbedProps} manifest partitioning — so
18
- * `blocks`-typed composition props are excluded (edited on the canvas) with a visible
19
- * note, and asset/relation/object props open their real pickers.
20
- *
21
- * Write-back is **immediate per prop change** (like the builder inspector): each edit
22
- * commits through the payload's `onChange` (one ProseMirror transaction upstream),
23
- * guarded by {@link resolveEmbedWrite} so an unchanged write never dirties the field.
24
- * There is no draft+Apply — the sidebar always reflects the committed node.
25
- *
26
- * TipTap-free by construction (see {@link EmbedInspectorPayload}) so the detail editor
27
- * can import it without pulling the editor runtime onto the critical path (EC-322).
28
- */
29
- export function EmbedInspector({ payload, className, }) {
30
- const { node, manifest, readOnly, onChange, onDeselect } = payload;
31
- const editable = editableEmbedProps(manifest);
32
- const blocks = blocksEmbedProps(manifest);
33
- function set(name, value) {
34
- const next = resolveEmbedWrite(node, setComponentNodeProp(node, name, value));
35
- if (next)
36
- onChange(next);
37
- }
38
- function clear(name) {
39
- const next = resolveEmbedWrite(node, clearComponentNodeProp(node, name));
40
- if (next)
41
- onChange(next);
42
- }
43
- return (_jsxs("div", { className: cn('flex h-full min-h-0 flex-col bg-card', className), children: [_jsxs(Row, { gap: "1", align: "center", className: "shrink-0 border-b border-border p-1.5", children: [_jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": translate('richText.embed.inspectorBack'), onClick: onDeselect, children: _jsx(ChevronLeft, { className: "size-4" }) }), _jsx(Text, { as: "span", size: "xs", weight: "semibold", className: "min-w-0 flex-1 truncate", children: componentDisplayName(node.componentId, manifest) })] }), _jsx("div", { className: "min-h-0 flex-1 overflow-auto p-3", children: _jsxs(Stack, { gap: "4", "aria-disabled": readOnly || undefined, className: cn(readOnly && 'pointer-events-none opacity-70'), children: [editable.length === 0 ? (_jsx(Text, { size: "sm", tone: "muted", children: translate('richText.embed.noProps') })) : (editable.map(([name, spec]) => {
44
- const id = `embed-${node.id}-${name}`;
45
- return (_jsx(Field, { label: localizedLabel(spec.form?.label, name), htmlFor: id, children: _jsx(PropValueControl, { id: id, name: name, spec: spec, value: node.props?.[name], onSet: (v) => set(name, v), onClear: () => clear(name) }) }, name));
46
- })), blocks.length > 0 ? (_jsxs(_Fragment, { children: [_jsx(Separator, {}), _jsx(Text, { size: "xs", tone: "subtle", children: translate('richText.embed.blocksNote') })] })) : null] }) })] }));
47
- }
48
- //# sourceMappingURL=embed-inspector.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"embed-inspector.js","sourceRoot":"","sources":["../../../../src/components/cms/rich-text/embed-inspector.tsx"],"names":[],"mappings":"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","sourcesContent":["import { ChevronLeft } from 'lucide-react'\nimport type { JsonValue } from '@elytracms/core/project-graph'\nimport { Button, Field, Row, Separator, Stack, Text } from '@elytracms/studio/ui'\nimport { localizedLabel, translate } from '@elytracms/studio/lib/i18n'\nimport { componentDisplayName } from '@elytracms/studio/lib/persona/labels'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { PropValueControl } from '../prop-fields'\nimport {\n blocksEmbedProps,\n clearComponentNodeProp,\n editableEmbedProps,\n resolveEmbedWrite,\n setComponentNodeProp,\n} from './embed-props'\nimport type { EmbedInspectorPayload } from './embed-inspector-context'\n\n/**\n * The selection-driven embed prop inspector (0.0.41) — the detail editor's right\n * sidebar swaps to this when a `componentEmbed` node is selected in a rich-text\n * field. It replaces the retired-for-this-surface {@link EmbedPropsDialog} modal so\n * embed props are edited in the SAME place document fields are, not a third form\n * surface (the product-owner feedback that motivated the change).\n *\n * It reuses the exact modal machinery — the EC-190 {@link PropValueControl} stack and\n * the {@link editableEmbedProps}/{@link blocksEmbedProps} manifest partitioning — so\n * `blocks`-typed composition props are excluded (edited on the canvas) with a visible\n * note, and asset/relation/object props open their real pickers.\n *\n * Write-back is **immediate per prop change** (like the builder inspector): each edit\n * commits through the payload's `onChange` (one ProseMirror transaction upstream),\n * guarded by {@link resolveEmbedWrite} so an unchanged write never dirties the field.\n * There is no draft+Apply — the sidebar always reflects the committed node.\n *\n * TipTap-free by construction (see {@link EmbedInspectorPayload}) so the detail editor\n * can import it without pulling the editor runtime onto the critical path (EC-322).\n */\nexport function EmbedInspector({\n payload,\n className,\n}: {\n payload: EmbedInspectorPayload\n className?: string\n}) {\n const { node, manifest, readOnly, onChange, onDeselect } = payload\n const editable = editableEmbedProps(manifest)\n const blocks = blocksEmbedProps(manifest)\n\n function set(name: string, value: JsonValue) {\n const next = resolveEmbedWrite(node, setComponentNodeProp(node, name, value))\n if (next) onChange(next)\n }\n function clear(name: string) {\n const next = resolveEmbedWrite(node, clearComponentNodeProp(node, name))\n if (next) onChange(next)\n }\n\n return (\n <div className={cn('flex h-full min-h-0 flex-col bg-card', className)}>\n <Row gap=\"1\" align=\"center\" className=\"shrink-0 border-b border-border p-1.5\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={translate('richText.embed.inspectorBack')}\n onClick={onDeselect}\n >\n <ChevronLeft className=\"size-4\" />\n </Button>\n <Text as=\"span\" size=\"xs\" weight=\"semibold\" className=\"min-w-0 flex-1 truncate\">\n {componentDisplayName(node.componentId, manifest)}\n </Text>\n </Row>\n <div className=\"min-h-0 flex-1 overflow-auto p-3\">\n <Stack\n gap=\"4\"\n aria-disabled={readOnly || undefined}\n className={cn(readOnly && 'pointer-events-none opacity-70')}\n >\n {editable.length === 0 ? (\n <Text size=\"sm\" tone=\"muted\">\n {translate('richText.embed.noProps')}\n </Text>\n ) : (\n editable.map(([name, spec]) => {\n const id = `embed-${node.id}-${name}`\n return (\n <Field key={name} label={localizedLabel(spec.form?.label, name)} htmlFor={id}>\n <PropValueControl\n id={id}\n name={name}\n spec={spec}\n value={node.props?.[name]}\n onSet={(v) => set(name, v)}\n onClear={() => clear(name)}\n />\n </Field>\n )\n })\n )}\n {blocks.length > 0 ? (\n <>\n <Separator />\n <Text size=\"xs\" tone=\"subtle\">\n {translate('richText.embed.blocksNote')}\n </Text>\n </>\n ) : null}\n </Stack>\n </div>\n </div>\n )\n}\n"]}
@@ -1,12 +0,0 @@
1
- import type { EmbedInspectorApi, EmbedInspectorPayload } from './rich-text/embed-inspector-context.js';
2
- /**
3
- * 0.0.41 — the selection-driven embed-inspector host. A `componentEmbed` node
4
- * selection in a rich-text field swaps the inspector sidebar for the embed's prop
5
- * form; deselect returns the normal inspector. `clearActiveEmbed` keys on the node
6
- * id so a fast A→B reselect can't let A's deselect wipe B (the selection race). Fed
7
- * by the rich-text field through the EmbedInspector context (the returned api).
8
- */
9
- export declare function useEmbedInspectorHost(): {
10
- activeEmbed: EmbedInspectorPayload | null;
11
- embedInspectorApi: EmbedInspectorApi;
12
- };
@@ -1,17 +0,0 @@
1
- import { useMemo, useState } from 'react';
2
- /**
3
- * 0.0.41 — the selection-driven embed-inspector host. A `componentEmbed` node
4
- * selection in a rich-text field swaps the inspector sidebar for the embed's prop
5
- * form; deselect returns the normal inspector. `clearActiveEmbed` keys on the node
6
- * id so a fast A→B reselect can't let A's deselect wipe B (the selection race). Fed
7
- * by the rich-text field through the EmbedInspector context (the returned api).
8
- */
9
- export function useEmbedInspectorHost() {
10
- const [activeEmbed, setActiveEmbed] = useState(null);
11
- const embedInspectorApi = useMemo(() => ({
12
- setActiveEmbed: (payload) => setActiveEmbed(payload),
13
- clearActiveEmbed: (nodeId) => setActiveEmbed((prev) => (prev?.nodeId === nodeId ? null : prev)),
14
- }), []);
15
- return { activeEmbed, embedInspectorApi };
16
- }
17
- //# sourceMappingURL=use-embed-inspector-host.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-embed-inspector-host.js","sourceRoot":"","sources":["../../../src/components/cms/use-embed-inspector-host.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAGzC;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB;IAInC,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAA+B,IAAI,CAAC,CAAA;IAClF,MAAM,iBAAiB,GAAG,OAAO,CAC/B,GAAG,EAAE,CAAC,CAAC;QACL,cAAc,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,cAAc,CAAC,OAAO,CAAC;QACpD,gBAAgB,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;KAChG,CAAC,EACF,EAAE,CACH,CAAA;IACD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,CAAA;AAC3C,CAAC","sourcesContent":["import { useMemo, useState } from 'react'\nimport type { EmbedInspectorApi, EmbedInspectorPayload } from './rich-text/embed-inspector-context'\n\n/**\n * 0.0.41 — the selection-driven embed-inspector host. A `componentEmbed` node\n * selection in a rich-text field swaps the inspector sidebar for the embed's prop\n * form; deselect returns the normal inspector. `clearActiveEmbed` keys on the node\n * id so a fast A→B reselect can't let A's deselect wipe B (the selection race). Fed\n * by the rich-text field through the EmbedInspector context (the returned api).\n */\nexport function useEmbedInspectorHost(): {\n activeEmbed: EmbedInspectorPayload | null\n embedInspectorApi: EmbedInspectorApi\n} {\n const [activeEmbed, setActiveEmbed] = useState<EmbedInspectorPayload | null>(null)\n const embedInspectorApi = useMemo<EmbedInspectorApi>(\n () => ({\n setActiveEmbed: (payload) => setActiveEmbed(payload),\n clearActiveEmbed: (nodeId) => setActiveEmbed((prev) => (prev?.nodeId === nodeId ? null : prev)),\n }),\n [],\n )\n return { activeEmbed, embedInspectorApi }\n}\n"]}