@contentful/experience-design-system-cli 2.38.1-dev-build-40e920ee.0 → 2.38.1-dev-build-db0347a4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/app.js CHANGED
@@ -19198,7 +19198,6 @@ function GotoBanner({
19198
19198
  borderStyle: "single",
19199
19199
  borderColor: PALETTE.accent,
19200
19200
  paddingX: 1,
19201
- paddingBottom: 1,
19202
19201
  marginTop: width === void 0 ? 1 : 0,
19203
19202
  width,
19204
19203
  flexShrink: 0,
@@ -19210,7 +19209,7 @@ function GotoBanner({
19210
19209
  return renderRow(row, i, i === highlightIndex);
19211
19210
  }),
19212
19211
  moreBelow > 0 && /* @__PURE__ */ jsx24(Text21, { color: PALETTE.muted, children: ` \u25BC ${moreBelow} more` }),
19213
- footerHint !== void 0 && /* @__PURE__ */ jsx24(Box21, { marginTop: 1, children: /* @__PURE__ */ jsx24(Text21, { color: PALETTE.muted, children: footerHint }) })
19212
+ footerHint !== void 0 && /* @__PURE__ */ jsx24(Text21, { color: PALETTE.muted, children: footerHint })
19214
19213
  ]
19215
19214
  }
19216
19215
  );
@@ -21715,7 +21714,7 @@ var capitalize = (name) => name.charAt(0).toUpperCase() + name.slice(1);
21715
21714
  function describeGeneration(input) {
21716
21715
  const agent = capitalize(input.agent);
21717
21716
  return `${formatAcceptanceSummary({ accepted: input.acceptedCount, autoRejected: 0 })}
21718
- ${agent} is reading each selected component and writing a Contentful component definition for it.${input.hasTokens ? "\nUsing your design tokens for prop resolution." : ""}`;
21717
+ ${agent} is reading each selected component and writing a Contentful component definition for it${input.hasTokens ? " Using your design tokens for prop resolution." : ""}`;
21719
21718
  }
21720
21719
  function progressRows2(progress, agent) {
21721
21720
  const name = capitalize(agent);
@@ -23373,6 +23372,7 @@ function FieldEditor({
23373
23372
  const [rationaleOpen, setRationaleOpen] = useState19(false);
23374
23373
  const [rationaleScrollOffset, setRationaleScrollOffset] = useState19(0);
23375
23374
  const [showHelp, setShowHelp] = useState19(false);
23375
+ const [pendingDelete, setPendingDelete] = useState19(null);
23376
23376
  const props = editorState.props;
23377
23377
  const slots = editorState.slots;
23378
23378
  const contentPropIndexes = React13.useMemo(
@@ -23464,6 +23464,46 @@ function FieldEditor({
23464
23464
  setEditorState(next);
23465
23465
  onChange(serializeState(next, value));
23466
23466
  };
23467
+ const deleteRow = (row) => {
23468
+ if (row.kind === "prop") {
23469
+ const nextProps = removeAt(editorState.props, row.idx);
23470
+ commit({ ...editorState, props: nextProps });
23471
+ setPropIdx(Math.max(0, Math.min(row.idx, nextProps.length - 1)));
23472
+ const rowsAfter2 = selectableRows.filter((r) => !(r.kind === "prop" && r.idx === row.idx));
23473
+ const neighbour2 = rowsAfter2[Math.max(0, selectableRows.findIndex((r) => r.kind === row.kind && r.idx === row.idx) - 1)];
23474
+ if (!neighbour2) {
23475
+ setInSlots(false);
23476
+ setInComponentDesc(true);
23477
+ setFocusLevel("componentDescription");
23478
+ } else if (neighbour2.kind === "prop") {
23479
+ setInSlots(false);
23480
+ setPropIdx(neighbour2.idx > row.idx ? neighbour2.idx - 1 : neighbour2.idx);
23481
+ setFocusLevel("prop");
23482
+ } else {
23483
+ setInSlots(true);
23484
+ setSlotIdx(neighbour2.idx);
23485
+ setFocusLevel("slot");
23486
+ }
23487
+ return;
23488
+ }
23489
+ const nextSlots = removeAt(editorState.slots, row.idx);
23490
+ commit({ ...editorState, slots: nextSlots });
23491
+ const rowsAfter = selectableRows.filter((r) => !(r.kind === "slot" && r.idx === row.idx));
23492
+ const neighbour = rowsAfter[Math.max(0, selectableRows.findIndex((r) => r.kind === row.kind && r.idx === row.idx) - 1)];
23493
+ if (!neighbour) {
23494
+ setInSlots(false);
23495
+ setInComponentDesc(true);
23496
+ setFocusLevel("componentDescription");
23497
+ } else if (neighbour.kind === "slot") {
23498
+ setInSlots(true);
23499
+ setSlotIdx(neighbour.idx > row.idx ? neighbour.idx - 1 : neighbour.idx);
23500
+ setFocusLevel("slot");
23501
+ } else {
23502
+ setInSlots(false);
23503
+ setPropIdx(neighbour.idx);
23504
+ setFocusLevel("prop");
23505
+ }
23506
+ };
23467
23507
  const canonicalize = React13.useCallback((json) => {
23468
23508
  try {
23469
23509
  return JSON.stringify(JSON.parse(json));
@@ -23500,6 +23540,11 @@ function FieldEditor({
23500
23540
  onSave();
23501
23541
  return;
23502
23542
  }
23543
+ if (pendingDelete) {
23544
+ if (input === "y") deleteRow(pendingDelete);
23545
+ setPendingDelete(null);
23546
+ return;
23547
+ }
23503
23548
  const inDescriptionTextEntryForHelp = focusLevel === "field" && editingField && activeField === "description";
23504
23549
  const inStringDefaultTextEntryForHelp = focusLevel === "field" && editingField && activeField === "default" && currentProp != null && (currentProp.type === "string" || currentProp.type === "token");
23505
23550
  const inValueListTextEntry = editingValue != null;
@@ -23699,6 +23744,11 @@ function FieldEditor({
23699
23744
  }
23700
23745
  return;
23701
23746
  }
23747
+ if (input === "d" && !key.ctrl && !key.meta) {
23748
+ if (focusLevel === "prop" && currentProp) setPendingDelete({ kind: "prop", idx: propIdx });
23749
+ if (focusLevel === "slot" && currentSlot) setPendingDelete({ kind: "slot", idx: slotIdx });
23750
+ return;
23751
+ }
23702
23752
  if (focusLevel === "slot" && key.return && currentSlot) {
23703
23753
  setFocusLevel("field");
23704
23754
  setActiveField(SLOT_FIELDS[0] ?? null);
@@ -24005,6 +24055,10 @@ function FieldEditor({
24005
24055
  }
24006
24056
  const hasEmptyProperties = props.length === 0 && slots.length === 0;
24007
24057
  const modeLabel = (() => {
24058
+ if (pendingDelete) {
24059
+ const name = pendingDelete.kind === "prop" ? props[pendingDelete.idx]?.name : slots[pendingDelete.idx]?.name;
24060
+ return `Delete ${pendingDelete.kind} "${name}"? [y] delete \xB7 any other key cancels`;
24061
+ }
24008
24062
  if (editingValue) {
24009
24063
  return editingValue.mode === "add" ? "Enter to add \xB7 [Esc] to cancel" : "Enter to save edit \xB7 [Esc] to cancel";
24010
24064
  }
@@ -24026,7 +24080,7 @@ function FieldEditor({
24026
24080
  if (rationaleOpen) {
24027
24081
  return "[\u2191\u2193] scroll [i/Esc] close rationale panel";
24028
24082
  }
24029
- return `[\u2191\u2193] navigate [Enter] edit fields [h] help [s] source [Esc] exit panel`;
24083
+ return `[\u2191\u2193] navigate [Enter] edit fields [d] delete property [h] help [s] source [Esc] exit panel`;
24030
24084
  })();
24031
24085
  const rows = [];
24032
24086
  rows.push({ kind: "component-description" });
@@ -24292,6 +24346,7 @@ function FieldEditor({
24292
24346
  /* @__PURE__ */ jsx32(Text27, { bold: true, children: "Row navigation" }),
24293
24347
  /* @__PURE__ */ jsx32(Text27, { children: " \u2191/\u2193 move between rows" }),
24294
24348
  /* @__PURE__ */ jsx32(Text27, { children: " Enter edit fields on the current row" }),
24349
+ /* @__PURE__ */ jsx32(Text27, { children: " d delete the current prop or slot (asks to confirm)" }),
24295
24350
  /* @__PURE__ */ jsx32(Text27, { children: " Esc exit the panel" }),
24296
24351
  /* @__PURE__ */ jsx32(Text27, { children: " " }),
24297
24352
  /* @__PURE__ */ jsx32(Text27, { bold: true, children: "Field editing" }),
@@ -24315,7 +24370,7 @@ function FieldEditor({
24315
24370
  /* @__PURE__ */ jsx32(Text27, { color: PALETTE.muted, children: "press ? or Esc to close" })
24316
24371
  ] }),
24317
24372
  validationError && /* @__PURE__ */ jsx32(Text27, { color: PALETTE.error, children: "\u2717 " + validationError }),
24318
- /* @__PURE__ */ jsx32(Box26, { paddingTop: 1, children: /* @__PURE__ */ jsx32(Text27, { color: PALETTE.muted, children: modeLabel }) })
24373
+ /* @__PURE__ */ jsx32(Box26, { paddingTop: 1, children: /* @__PURE__ */ jsx32(Text27, { color: pendingDelete ? PALETTE.text : PALETTE.muted, children: modeLabel }) })
24319
24374
  ]
24320
24375
  }
24321
24376
  );
@@ -24654,8 +24709,8 @@ function TokenReviewPanel({
24654
24709
  borderStyle: "single",
24655
24710
  borderColor: active ? PALETTE.text : void 0,
24656
24711
  children: [
24657
- /* @__PURE__ */ jsx39(Text32, { bold: true, color: active ? void 0 : PALETTE.muted, wrap: "truncate", children: `Review mapped tokens \u2014 ${componentName} \xB7 ${current.propName}${current.kinds.length > 0 ? ` (${current.kinds.join(", ")})` : ""}` }),
24658
- /* @__PURE__ */ jsx39(Text32, { color: PALETTE.muted, wrap: "truncate", children: `Tick the tokens this property may use (${rangeLabel}).` }),
24712
+ /* @__PURE__ */ jsx39(Text32, { bold: true, color: active ? void 0 : PALETTE.muted, wrap: "truncate", children: `TOKEN REVIEW \u2014 ${componentName} \xB7 ${current.propName} (edit allowed)` }),
24713
+ /* @__PURE__ */ jsx39(Text32, { color: PALETTE.muted, wrap: "truncate", children: `select which tokens are allowed (${rangeLabel})` }),
24659
24714
  /* @__PURE__ */ jsx39(Text32, { children: " " }),
24660
24715
  current.paths.length === 0 && /* @__PURE__ */ jsx39(Text32, { color: PALETTE.muted, children: "(no compatible tokens found for this token kind)" }),
24661
24716
  visiblePaths.map((path5, i) => {
@@ -24688,33 +24743,18 @@ function TokenReviewPanel({
24688
24743
  borderStyle: "single",
24689
24744
  borderColor: active ? PALETTE.text : void 0,
24690
24745
  children: [
24691
- /* @__PURE__ */ jsx39(Text32, { bold: true, color: active ? void 0 : PALETTE.muted, children: `Review mapped tokens \u2014 ${componentName}` }),
24692
- /* @__PURE__ */ jsx39(Text32, { color: PALETTE.muted, wrap: "truncate", children: `${componentName} has ${suggestions.length} design ${suggestions.length === 1 ? "prop" : "props"} of type token. Select which tokens are allowed for each property.` }),
24693
- /* @__PURE__ */ jsx39(Text32, { color: PALETTE.muted, wrap: "truncate", children: "Suggested tokens come from the agent. Allowed tokens are what editors can pick in Contentful." }),
24694
- /* @__PURE__ */ jsx39(Text32, { children: " " }),
24746
+ /* @__PURE__ */ jsx39(Text32, { bold: true, color: active ? void 0 : PALETTE.muted, children: `TOKEN REVIEW \u2014 ${componentName}` }),
24695
24747
  suggestions.length === 0 && /* @__PURE__ */ jsx39(Text32, { color: PALETTE.muted, children: "(no token suggestions for this component)" }),
24696
24748
  suggestions.map((s, i) => {
24697
24749
  const focused = i === selectedRow;
24698
24750
  return /* @__PURE__ */ jsxs30(Box31, { flexDirection: "column", children: [
24699
- /* @__PURE__ */ jsx39(Box31, { children: /* @__PURE__ */ jsx39(Text32, { color: focused ? PALETTE.accent : active ? void 0 : PALETTE.muted, bold: focused, children: `${focused ? figures7.pointer : " "} ${s.propName}${s.kinds.length > 0 ? ` (${s.kinds.join(", ")})` : ""}` }) }),
24700
- /* @__PURE__ */ jsx39(
24701
- Text32,
24702
- {
24703
- color: PALETTE.muted,
24704
- children: ` suggested: ${s.suggested.length > 0 ? s.suggested.join(", ") : "none"}`
24705
- }
24706
- ),
24707
- /* @__PURE__ */ jsx39(
24708
- Text32,
24709
- {
24710
- color: PALETTE.muted,
24711
- children: ` allowed: ${s.allowed.length > 0 ? s.allowed.join(", ") : "none (any token)"}`
24712
- }
24713
- ),
24714
- /* @__PURE__ */ jsx39(Text32, { children: " " })
24751
+ /* @__PURE__ */ jsx39(Box31, { children: /* @__PURE__ */ jsx39(Text32, { color: focused ? PALETTE.accent : active ? void 0 : PALETTE.muted, bold: focused, children: `${focused ? figures7.pointer : " "} ${s.propName}` }) }),
24752
+ /* @__PURE__ */ jsx39(Text32, { color: PALETTE.muted, children: ` suggested: ${s.suggested.join(", ")}` }),
24753
+ /* @__PURE__ */ jsx39(Text32, { color: PALETTE.muted, children: ` allowed: ${s.allowed.join(", ")}` })
24715
24754
  ] }, s.propName);
24716
24755
  }),
24717
- /* @__PURE__ */ jsx39(Text32, { color: PALETTE.muted, children: "[\u2191/\u2193] move [Enter] edit allowed tokens [Esc] close" })
24756
+ /* @__PURE__ */ jsx39(Text32, { children: " " }),
24757
+ /* @__PURE__ */ jsx39(Text32, { children: "[\u2191/\u2193] move [Enter] edit allowed [Esc] close" })
24718
24758
  ]
24719
24759
  }
24720
24760
  );
@@ -24962,9 +25002,15 @@ function ReviewFinalizeError({
24962
25002
  function ReviewPanelFooter({
24963
25003
  reviewEditor,
24964
25004
  sidebarFocused,
24965
- sidebarFooter
25005
+ sidebarFooter,
25006
+ livePreview,
25007
+ livePreviewSpinner
24966
25008
  }) {
24967
- return /* @__PURE__ */ jsx42(Fragment10, { children: reviewEditor.panelOpen === "token-review" ? "" : sidebarFocused ? sidebarFooter : reviewEditor.showJson ? " [\u2191\u2193] scroll [Ctrl+u/d] half-page [gg/G] top/bottom [Tab] focus list" : " [Tab] focus list [Enter] edit fields" + (reviewEditor.currentTokenSuggestions().length > 0 ? " [t] review mapped tokens" : "") });
25009
+ return /* @__PURE__ */ jsxs32(Fragment10, { children: [
25010
+ reviewEditor.panelOpen === "token-review" ? " [\u2191/\u2193] move [Enter] edit allowed [Esc] close" : sidebarFocused ? sidebarFooter : reviewEditor.showJson ? " [\u2191\u2193] scroll [Ctrl+u/d] half-page [gg/G] top/bottom [Tab] focus list" : " [Tab] focus list (edit fields)" + (reviewEditor.currentTokenSuggestions().length > 0 ? " [t] token review" : ""),
25011
+ livePreview.status === "running" && /* @__PURE__ */ jsx42(Text34, { children: ` ${livePreviewSpinner} live preview` }),
25012
+ livePreview.disabled && /* @__PURE__ */ jsx42(Text34, { children: " \xB7 live preview disabled" })
25013
+ ] });
24968
25014
  }
24969
25015
  function ReviewComponentTitle({
24970
25016
  selectedKey,
@@ -24998,7 +25044,9 @@ function ReviewComponentPanel({
24998
25044
  sidebarFocused,
24999
25045
  fieldEditor,
25000
25046
  saveError,
25001
- sidebarFooter
25047
+ sidebarFooter,
25048
+ livePreview,
25049
+ livePreviewSpinner
25002
25050
  }) {
25003
25051
  const propCount = Object.keys(selectedEntry.$properties).length;
25004
25052
  const slotCount = selectedEntry.$slots ? Object.keys(selectedEntry.$slots).length : 0;
@@ -25035,7 +25083,9 @@ function ReviewComponentPanel({
25035
25083
  {
25036
25084
  reviewEditor,
25037
25085
  sidebarFocused,
25038
- sidebarFooter
25086
+ sidebarFooter,
25087
+ livePreview,
25088
+ livePreviewSpinner
25039
25089
  }
25040
25090
  ) }) })
25041
25091
  ] }) });
@@ -25579,7 +25629,7 @@ function collectTokenSuggestions(entry, availableTokens = []) {
25579
25629
  const compatiblePaths = new Set(compatible);
25580
25630
  const allowed = availableTokens.length > 0 ? persistedAllowed.filter((path5) => compatiblePaths.has(path5)) : persistedAllowed;
25581
25631
  const paths = availableTokens.length > 0 ? compatible : allowed;
25582
- return { propName, kinds, paths, suggested: [...allowed], allowed };
25632
+ return { propName, paths, suggested: [...allowed], allowed };
25583
25633
  });
25584
25634
  }
25585
25635
 
@@ -26375,7 +26425,7 @@ var HELP_SECTIONS2 = [
26375
26425
  { keys: "P", label: "Component rationale" },
26376
26426
  { keys: "s", label: "Source code snippet" },
26377
26427
  { keys: "J", label: "Toggle JSON" },
26378
- { keys: "t", label: "Review mapped tokens" }
26428
+ { keys: "t", label: "Token review" }
26379
26429
  ]
26380
26430
  },
26381
26431
  {
@@ -27523,7 +27573,9 @@ function GenerateReviewStepView({
27523
27573
  initialFocusTarget: pendingEditorFocus && pendingEditorFocus.componentName === selected.key ? pendingEditorFocus.target : { kind: "description" }
27524
27574
  }
27525
27575
  ),
27526
- saveError: reviewEditor.saveError
27576
+ saveError: reviewEditor.saveError,
27577
+ livePreview: livePreviewHook,
27578
+ livePreviewSpinner
27527
27579
  }
27528
27580
  ) : /* @__PURE__ */ jsx48(ReviewNoSelection, {})
27529
27581
  ] }),
@@ -27555,7 +27607,7 @@ function GenerateReviewStepView({
27555
27607
  hidden: dialogOpen
27556
27608
  }
27557
27609
  ),
27558
- !dialogOpen && sidebarFocused && reviewEditor.panelOpen !== "token-review" && /* @__PURE__ */ jsx48(CompactControlBar, { hasGroupRoots, searchActive: searchOpen || searchQuery.length > 0 })
27610
+ !dialogOpen && sidebarFocused && /* @__PURE__ */ jsx48(CompactControlBar, { hasGroupRoots, searchActive: searchOpen || searchQuery.length > 0 })
27559
27611
  ] });
27560
27612
  }
27561
27613
 
@@ -27759,7 +27811,8 @@ function PathPrompt({
27759
27811
  defaultPath,
27760
27812
  onSubmit,
27761
27813
  onCancel,
27762
- label = "Save to"
27814
+ label = "Save to",
27815
+ summary
27763
27816
  }) {
27764
27817
  const [input, setInput] = useState28("");
27765
27818
  const cursorVisible = useBlinkingCursor();
@@ -27793,6 +27846,7 @@ function PathPrompt({
27793
27846
  return /* @__PURE__ */ jsxs42(Box42, { flexDirection: "column", children: [
27794
27847
  /* @__PURE__ */ jsx52(StepHeader, { step: "push" }),
27795
27848
  /* @__PURE__ */ jsxs42(Box42, { flexDirection: "column", gap: 1, paddingX: 2, paddingBottom: 1, children: [
27849
+ summary && /* @__PURE__ */ jsx52(Text44, { color: PALETTE.muted, children: summary }),
27796
27850
  /* @__PURE__ */ jsxs42(Box42, { gap: 1, children: [
27797
27851
  /* @__PURE__ */ jsx52(Text44, { color: PALETTE.accent, children: "?" }),
27798
27852
  /* @__PURE__ */ jsxs42(Text44, { bold: true, children: [
@@ -27827,9 +27881,15 @@ function producedOf(state2) {
27827
27881
  function fileSummaryLabel({ components }) {
27828
27882
  return components ? "components.json" : "components.json (design tokens only)";
27829
27883
  }
27830
- function writtenThings({ components, tokens }) {
27831
- if (components && tokens) return "component types and design tokens";
27832
- return tokens ? "design tokens" : "component types";
27884
+ function counted(count, noun) {
27885
+ if (!count) return `${noun}s`;
27886
+ return `${count} ${noun}${count === 1 ? "" : "s"}`;
27887
+ }
27888
+ function countedThings({ components, tokens }, counts = {}) {
27889
+ const parts = [];
27890
+ if (components || !tokens) parts.push(counted(counts.components, "component type"));
27891
+ if (tokens) parts.push(counted(counts.tokens, "design token"));
27892
+ return parts.join(" and ");
27833
27893
  }
27834
27894
 
27835
27895
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/support/use-timed-spinner.tsx
@@ -27854,18 +27914,21 @@ function useTimedSpinner() {
27854
27914
 
27855
27915
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/screens/PushingStep.tsx
27856
27916
  import { jsx as jsx54, jsxs as jsxs43 } from "react/jsx-runtime";
27857
- function PushingStep({ progress, produced }) {
27858
- const { elapsed } = useTimedSpinner();
27917
+ function PushingStep({ progress, produced, counts }) {
27918
+ const { spinner, elapsed } = useTimedSpinner();
27859
27919
  const operationId = progress && progress.kind === "queued" ? progress.operationId : null;
27860
27920
  const showGlobal = progress && progress.kind === "progress";
27861
27921
  const showCurrent = progress && progress.kind === "progress" && progress.current ? progress.current : null;
27862
27922
  return /* @__PURE__ */ jsxs43(Box43, { flexDirection: "column", children: [
27863
27923
  /* @__PURE__ */ jsx54(StepHeader, { step: "push" }),
27864
27924
  /* @__PURE__ */ jsxs43(Box43, { flexDirection: "column", gap: 1, paddingX: 2, paddingBottom: 1, children: [
27865
- /* @__PURE__ */ jsxs43(Text45, { children: [
27866
- "Writing ",
27867
- writtenThings(produced),
27868
- " to your Contentful space..."
27925
+ /* @__PURE__ */ jsxs43(Box43, { gap: 1, children: [
27926
+ spinner,
27927
+ /* @__PURE__ */ jsxs43(Text45, { children: [
27928
+ "Writing ",
27929
+ countedThings(produced, counts),
27930
+ " to your Contentful space..."
27931
+ ] })
27869
27932
  ] }),
27870
27933
  operationId && /* @__PURE__ */ jsxs43(Box43, { gap: 1, children: [
27871
27934
  /* @__PURE__ */ jsx54(Text45, { color: PALETTE.muted, children: "Operation:" }),
@@ -28034,20 +28097,12 @@ function diffProperty(name, old, newDef) {
28034
28097
  diffs.push({ key: `${name}-new`, color: PALETTE.success, text: `+ ${name}: ${formatPropDef(newDef)}` });
28035
28098
  return diffs;
28036
28099
  }
28037
- function formatDefault(value) {
28038
- const sys = value?.sys;
28039
- if (sys?.linkType === "Contentful:DesignToken" && typeof sys.urn === "string") {
28040
- const name = sys.urn.split("/designTokens/")[1];
28041
- if (name) return name;
28042
- }
28043
- return JSON.stringify(value);
28044
- }
28045
28100
  function formatOldProp(prop) {
28046
28101
  const parts = [];
28047
28102
  if (prop.type) parts.push(prop.type);
28048
28103
  if (prop.category) parts.push(prop.category);
28049
28104
  parts.push(prop.required ? "required" : "optional");
28050
- if (prop.default !== void 0) parts.push(`default=${formatDefault(prop.default)}`);
28105
+ if (prop.default !== void 0) parts.push(`default=${JSON.stringify(prop.default)}`);
28051
28106
  return parts.join(", ");
28052
28107
  }
28053
28108
  function formatPropDef(def) {
@@ -28056,7 +28111,7 @@ function formatPropDef(def) {
28056
28111
  if (def["$category"]) parts.push(def["$category"]);
28057
28112
  if (def["$required"] === true) parts.push("required");
28058
28113
  else parts.push("optional");
28059
- if (def["$default"] !== void 0) parts.push(`default=${formatDefault(def["$default"])}`);
28114
+ if (def["$default"] !== void 0) parts.push(`default=${JSON.stringify(def["$default"])}`);
28060
28115
  return parts.join(", ");
28061
28116
  }
28062
28117
 
@@ -28392,6 +28447,8 @@ function FlowScreen({
28392
28447
  onExit
28393
28448
  }) {
28394
28449
  const produced = producedOf(state2);
28450
+ const counts = { components: state2.generatedAcceptedCount, tokens: state2.tokenCount };
28451
+ const things = countedThings(produced, counts);
28395
28452
  const quit = () => onExit(0);
28396
28453
  const content = (() => {
28397
28454
  switch (state2.step) {
@@ -28413,7 +28470,7 @@ function FlowScreen({
28413
28470
  }
28414
28471
  );
28415
28472
  case "previewing":
28416
- return /* @__PURE__ */ jsx56(RunningStep, { step: "push", description: "Computing diff against your Contentful space..." });
28473
+ return /* @__PURE__ */ jsx56(RunningStep, { step: "push", description: `Computing diff for ${things} against your Contentful space...` });
28417
28474
  case "preview-gate":
28418
28475
  if (!state2.serverPreview) return null;
28419
28476
  return /* @__PURE__ */ jsx56(
@@ -28428,11 +28485,12 @@ function FlowScreen({
28428
28485
  }
28429
28486
  );
28430
28487
  case "pushing":
28431
- return /* @__PURE__ */ jsx56(PushingStep, { progress: state2.pushProgress, produced });
28488
+ return /* @__PURE__ */ jsx56(PushingStep, { progress: state2.pushProgress, produced, counts });
28432
28489
  case "path-prompt":
28433
28490
  return /* @__PURE__ */ jsx56(
28434
28491
  PathPrompt,
28435
28492
  {
28493
+ summary: `Saving ${things}${state2.credentialsSkipped ? "" : " and pushing them to your Contentful space"}.`,
28436
28494
  defaultPath: state2.outDir,
28437
28495
  onSubmit: (submitted) => void controller.submitPath(submitted),
28438
28496
  onCancel: quit
package/dist/index.js CHANGED
@@ -21792,7 +21792,6 @@ function GotoBanner({
21792
21792
  borderStyle: "single",
21793
21793
  borderColor: PALETTE.accent,
21794
21794
  paddingX: 1,
21795
- paddingBottom: 1,
21796
21795
  marginTop: width === void 0 ? 1 : 0,
21797
21796
  width,
21798
21797
  flexShrink: 0,
@@ -21804,7 +21803,7 @@ function GotoBanner({
21804
21803
  return renderRow(row, i, i === highlightIndex);
21805
21804
  }),
21806
21805
  moreBelow > 0 && /* @__PURE__ */ jsx24(Text21, { color: PALETTE.muted, children: ` \u25BC ${moreBelow} more` }),
21807
- footerHint !== void 0 && /* @__PURE__ */ jsx24(Box21, { marginTop: 1, children: /* @__PURE__ */ jsx24(Text21, { color: PALETTE.muted, children: footerHint }) })
21806
+ footerHint !== void 0 && /* @__PURE__ */ jsx24(Text21, { color: PALETTE.muted, children: footerHint })
21808
21807
  ]
21809
21808
  }
21810
21809
  );
@@ -24536,7 +24535,7 @@ function formatAcceptanceSummary(counts) {
24536
24535
  function describeGeneration(input) {
24537
24536
  const agent = capitalize(input.agent);
24538
24537
  return `${formatAcceptanceSummary({ accepted: input.acceptedCount, autoRejected: 0 })}
24539
- ${agent} is reading each selected component and writing a Contentful component definition for it.${input.hasTokens ? "\nUsing your design tokens for prop resolution." : ""}`;
24538
+ ${agent} is reading each selected component and writing a Contentful component definition for it${input.hasTokens ? " Using your design tokens for prop resolution." : ""}`;
24540
24539
  }
24541
24540
  function progressRows2(progress, agent) {
24542
24541
  const name = capitalize(agent);
@@ -26401,6 +26400,7 @@ function FieldEditor({
26401
26400
  const [rationaleOpen, setRationaleOpen] = useState19(false);
26402
26401
  const [rationaleScrollOffset, setRationaleScrollOffset] = useState19(0);
26403
26402
  const [showHelp, setShowHelp] = useState19(false);
26403
+ const [pendingDelete, setPendingDelete] = useState19(null);
26404
26404
  const props = editorState.props;
26405
26405
  const slots = editorState.slots;
26406
26406
  const contentPropIndexes = React13.useMemo(
@@ -26492,6 +26492,46 @@ function FieldEditor({
26492
26492
  setEditorState(next);
26493
26493
  onChange(serializeState(next, value));
26494
26494
  };
26495
+ const deleteRow = (row) => {
26496
+ if (row.kind === "prop") {
26497
+ const nextProps = removeAt(editorState.props, row.idx);
26498
+ commit({ ...editorState, props: nextProps });
26499
+ setPropIdx(Math.max(0, Math.min(row.idx, nextProps.length - 1)));
26500
+ const rowsAfter2 = selectableRows.filter((r) => !(r.kind === "prop" && r.idx === row.idx));
26501
+ const neighbour2 = rowsAfter2[Math.max(0, selectableRows.findIndex((r) => r.kind === row.kind && r.idx === row.idx) - 1)];
26502
+ if (!neighbour2) {
26503
+ setInSlots(false);
26504
+ setInComponentDesc(true);
26505
+ setFocusLevel("componentDescription");
26506
+ } else if (neighbour2.kind === "prop") {
26507
+ setInSlots(false);
26508
+ setPropIdx(neighbour2.idx > row.idx ? neighbour2.idx - 1 : neighbour2.idx);
26509
+ setFocusLevel("prop");
26510
+ } else {
26511
+ setInSlots(true);
26512
+ setSlotIdx(neighbour2.idx);
26513
+ setFocusLevel("slot");
26514
+ }
26515
+ return;
26516
+ }
26517
+ const nextSlots = removeAt(editorState.slots, row.idx);
26518
+ commit({ ...editorState, slots: nextSlots });
26519
+ const rowsAfter = selectableRows.filter((r) => !(r.kind === "slot" && r.idx === row.idx));
26520
+ const neighbour = rowsAfter[Math.max(0, selectableRows.findIndex((r) => r.kind === row.kind && r.idx === row.idx) - 1)];
26521
+ if (!neighbour) {
26522
+ setInSlots(false);
26523
+ setInComponentDesc(true);
26524
+ setFocusLevel("componentDescription");
26525
+ } else if (neighbour.kind === "slot") {
26526
+ setInSlots(true);
26527
+ setSlotIdx(neighbour.idx > row.idx ? neighbour.idx - 1 : neighbour.idx);
26528
+ setFocusLevel("slot");
26529
+ } else {
26530
+ setInSlots(false);
26531
+ setPropIdx(neighbour.idx);
26532
+ setFocusLevel("prop");
26533
+ }
26534
+ };
26495
26535
  const canonicalize = React13.useCallback((json) => {
26496
26536
  try {
26497
26537
  return JSON.stringify(JSON.parse(json));
@@ -26528,6 +26568,11 @@ function FieldEditor({
26528
26568
  onSave();
26529
26569
  return;
26530
26570
  }
26571
+ if (pendingDelete) {
26572
+ if (input === "y") deleteRow(pendingDelete);
26573
+ setPendingDelete(null);
26574
+ return;
26575
+ }
26531
26576
  const inDescriptionTextEntryForHelp = focusLevel === "field" && editingField && activeField === "description";
26532
26577
  const inStringDefaultTextEntryForHelp = focusLevel === "field" && editingField && activeField === "default" && currentProp != null && (currentProp.type === "string" || currentProp.type === "token");
26533
26578
  const inValueListTextEntry = editingValue != null;
@@ -26727,6 +26772,11 @@ function FieldEditor({
26727
26772
  }
26728
26773
  return;
26729
26774
  }
26775
+ if (input === "d" && !key.ctrl && !key.meta) {
26776
+ if (focusLevel === "prop" && currentProp) setPendingDelete({ kind: "prop", idx: propIdx });
26777
+ if (focusLevel === "slot" && currentSlot) setPendingDelete({ kind: "slot", idx: slotIdx });
26778
+ return;
26779
+ }
26730
26780
  if (focusLevel === "slot" && key.return && currentSlot) {
26731
26781
  setFocusLevel("field");
26732
26782
  setActiveField(SLOT_FIELDS[0] ?? null);
@@ -27033,6 +27083,10 @@ function FieldEditor({
27033
27083
  }
27034
27084
  const hasEmptyProperties = props.length === 0 && slots.length === 0;
27035
27085
  const modeLabel = (() => {
27086
+ if (pendingDelete) {
27087
+ const name = pendingDelete.kind === "prop" ? props[pendingDelete.idx]?.name : slots[pendingDelete.idx]?.name;
27088
+ return `Delete ${pendingDelete.kind} "${name}"? [y] delete \xB7 any other key cancels`;
27089
+ }
27036
27090
  if (editingValue) {
27037
27091
  return editingValue.mode === "add" ? "Enter to add \xB7 [Esc] to cancel" : "Enter to save edit \xB7 [Esc] to cancel";
27038
27092
  }
@@ -27054,7 +27108,7 @@ function FieldEditor({
27054
27108
  if (rationaleOpen) {
27055
27109
  return "[\u2191\u2193] scroll [i/Esc] close rationale panel";
27056
27110
  }
27057
- return `[\u2191\u2193] navigate [Enter] edit fields [h] help [s] source [Esc] exit panel`;
27111
+ return `[\u2191\u2193] navigate [Enter] edit fields [d] delete property [h] help [s] source [Esc] exit panel`;
27058
27112
  })();
27059
27113
  const rows = [];
27060
27114
  rows.push({ kind: "component-description" });
@@ -27320,6 +27374,7 @@ function FieldEditor({
27320
27374
  /* @__PURE__ */ jsx32(Text27, { bold: true, children: "Row navigation" }),
27321
27375
  /* @__PURE__ */ jsx32(Text27, { children: " \u2191/\u2193 move between rows" }),
27322
27376
  /* @__PURE__ */ jsx32(Text27, { children: " Enter edit fields on the current row" }),
27377
+ /* @__PURE__ */ jsx32(Text27, { children: " d delete the current prop or slot (asks to confirm)" }),
27323
27378
  /* @__PURE__ */ jsx32(Text27, { children: " Esc exit the panel" }),
27324
27379
  /* @__PURE__ */ jsx32(Text27, { children: " " }),
27325
27380
  /* @__PURE__ */ jsx32(Text27, { bold: true, children: "Field editing" }),
@@ -27343,7 +27398,7 @@ function FieldEditor({
27343
27398
  /* @__PURE__ */ jsx32(Text27, { color: PALETTE.muted, children: "press ? or Esc to close" })
27344
27399
  ] }),
27345
27400
  validationError && /* @__PURE__ */ jsx32(Text27, { color: PALETTE.error, children: "\u2717 " + validationError }),
27346
- /* @__PURE__ */ jsx32(Box26, { paddingTop: 1, children: /* @__PURE__ */ jsx32(Text27, { color: PALETTE.muted, children: modeLabel }) })
27401
+ /* @__PURE__ */ jsx32(Box26, { paddingTop: 1, children: /* @__PURE__ */ jsx32(Text27, { color: pendingDelete ? PALETTE.text : PALETTE.muted, children: modeLabel }) })
27347
27402
  ]
27348
27403
  }
27349
27404
  );
@@ -27736,8 +27791,8 @@ function TokenReviewPanel({
27736
27791
  borderStyle: "single",
27737
27792
  borderColor: active ? PALETTE.text : void 0,
27738
27793
  children: [
27739
- /* @__PURE__ */ jsx39(Text32, { bold: true, color: active ? void 0 : PALETTE.muted, wrap: "truncate", children: `Review mapped tokens \u2014 ${componentName} \xB7 ${current.propName}${current.kinds.length > 0 ? ` (${current.kinds.join(", ")})` : ""}` }),
27740
- /* @__PURE__ */ jsx39(Text32, { color: PALETTE.muted, wrap: "truncate", children: `Tick the tokens this property may use (${rangeLabel}).` }),
27794
+ /* @__PURE__ */ jsx39(Text32, { bold: true, color: active ? void 0 : PALETTE.muted, wrap: "truncate", children: `TOKEN REVIEW \u2014 ${componentName} \xB7 ${current.propName} (edit allowed)` }),
27795
+ /* @__PURE__ */ jsx39(Text32, { color: PALETTE.muted, wrap: "truncate", children: `select which tokens are allowed (${rangeLabel})` }),
27741
27796
  /* @__PURE__ */ jsx39(Text32, { children: " " }),
27742
27797
  current.paths.length === 0 && /* @__PURE__ */ jsx39(Text32, { color: PALETTE.muted, children: "(no compatible tokens found for this token kind)" }),
27743
27798
  visiblePaths.map((path5, i) => {
@@ -27770,33 +27825,18 @@ function TokenReviewPanel({
27770
27825
  borderStyle: "single",
27771
27826
  borderColor: active ? PALETTE.text : void 0,
27772
27827
  children: [
27773
- /* @__PURE__ */ jsx39(Text32, { bold: true, color: active ? void 0 : PALETTE.muted, children: `Review mapped tokens \u2014 ${componentName}` }),
27774
- /* @__PURE__ */ jsx39(Text32, { color: PALETTE.muted, wrap: "truncate", children: `${componentName} has ${suggestions.length} design ${suggestions.length === 1 ? "prop" : "props"} of type token. Select which tokens are allowed for each property.` }),
27775
- /* @__PURE__ */ jsx39(Text32, { color: PALETTE.muted, wrap: "truncate", children: "Suggested tokens come from the agent. Allowed tokens are what editors can pick in Contentful." }),
27776
- /* @__PURE__ */ jsx39(Text32, { children: " " }),
27828
+ /* @__PURE__ */ jsx39(Text32, { bold: true, color: active ? void 0 : PALETTE.muted, children: `TOKEN REVIEW \u2014 ${componentName}` }),
27777
27829
  suggestions.length === 0 && /* @__PURE__ */ jsx39(Text32, { color: PALETTE.muted, children: "(no token suggestions for this component)" }),
27778
27830
  suggestions.map((s, i) => {
27779
27831
  const focused = i === selectedRow;
27780
27832
  return /* @__PURE__ */ jsxs30(Box31, { flexDirection: "column", children: [
27781
- /* @__PURE__ */ jsx39(Box31, { children: /* @__PURE__ */ jsx39(Text32, { color: focused ? PALETTE.accent : active ? void 0 : PALETTE.muted, bold: focused, children: `${focused ? figures7.pointer : " "} ${s.propName}${s.kinds.length > 0 ? ` (${s.kinds.join(", ")})` : ""}` }) }),
27782
- /* @__PURE__ */ jsx39(
27783
- Text32,
27784
- {
27785
- color: PALETTE.muted,
27786
- children: ` suggested: ${s.suggested.length > 0 ? s.suggested.join(", ") : "none"}`
27787
- }
27788
- ),
27789
- /* @__PURE__ */ jsx39(
27790
- Text32,
27791
- {
27792
- color: PALETTE.muted,
27793
- children: ` allowed: ${s.allowed.length > 0 ? s.allowed.join(", ") : "none (any token)"}`
27794
- }
27795
- ),
27796
- /* @__PURE__ */ jsx39(Text32, { children: " " })
27833
+ /* @__PURE__ */ jsx39(Box31, { children: /* @__PURE__ */ jsx39(Text32, { color: focused ? PALETTE.accent : active ? void 0 : PALETTE.muted, bold: focused, children: `${focused ? figures7.pointer : " "} ${s.propName}` }) }),
27834
+ /* @__PURE__ */ jsx39(Text32, { color: PALETTE.muted, children: ` suggested: ${s.suggested.join(", ")}` }),
27835
+ /* @__PURE__ */ jsx39(Text32, { color: PALETTE.muted, children: ` allowed: ${s.allowed.join(", ")}` })
27797
27836
  ] }, s.propName);
27798
27837
  }),
27799
- /* @__PURE__ */ jsx39(Text32, { color: PALETTE.muted, children: "[\u2191/\u2193] move [Enter] edit allowed tokens [Esc] close" })
27838
+ /* @__PURE__ */ jsx39(Text32, { children: " " }),
27839
+ /* @__PURE__ */ jsx39(Text32, { children: "[\u2191/\u2193] move [Enter] edit allowed [Esc] close" })
27800
27840
  ]
27801
27841
  }
27802
27842
  );
@@ -28070,9 +28110,15 @@ function ReviewFinalizeError({
28070
28110
  function ReviewPanelFooter({
28071
28111
  reviewEditor,
28072
28112
  sidebarFocused,
28073
- sidebarFooter
28113
+ sidebarFooter,
28114
+ livePreview,
28115
+ livePreviewSpinner
28074
28116
  }) {
28075
- return /* @__PURE__ */ jsx42(Fragment10, { children: reviewEditor.panelOpen === "token-review" ? "" : sidebarFocused ? sidebarFooter : reviewEditor.showJson ? " [\u2191\u2193] scroll [Ctrl+u/d] half-page [gg/G] top/bottom [Tab] focus list" : " [Tab] focus list [Enter] edit fields" + (reviewEditor.currentTokenSuggestions().length > 0 ? " [t] review mapped tokens" : "") });
28117
+ return /* @__PURE__ */ jsxs32(Fragment10, { children: [
28118
+ reviewEditor.panelOpen === "token-review" ? " [\u2191/\u2193] move [Enter] edit allowed [Esc] close" : sidebarFocused ? sidebarFooter : reviewEditor.showJson ? " [\u2191\u2193] scroll [Ctrl+u/d] half-page [gg/G] top/bottom [Tab] focus list" : " [Tab] focus list (edit fields)" + (reviewEditor.currentTokenSuggestions().length > 0 ? " [t] token review" : ""),
28119
+ livePreview.status === "running" && /* @__PURE__ */ jsx42(Text34, { children: ` ${livePreviewSpinner} live preview` }),
28120
+ livePreview.disabled && /* @__PURE__ */ jsx42(Text34, { children: " \xB7 live preview disabled" })
28121
+ ] });
28076
28122
  }
28077
28123
  function ReviewComponentTitle({
28078
28124
  selectedKey,
@@ -28106,7 +28152,9 @@ function ReviewComponentPanel({
28106
28152
  sidebarFocused,
28107
28153
  fieldEditor,
28108
28154
  saveError,
28109
- sidebarFooter
28155
+ sidebarFooter,
28156
+ livePreview,
28157
+ livePreviewSpinner
28110
28158
  }) {
28111
28159
  const propCount = Object.keys(selectedEntry.$properties).length;
28112
28160
  const slotCount = selectedEntry.$slots ? Object.keys(selectedEntry.$slots).length : 0;
@@ -28143,7 +28191,9 @@ function ReviewComponentPanel({
28143
28191
  {
28144
28192
  reviewEditor,
28145
28193
  sidebarFocused,
28146
- sidebarFooter
28194
+ sidebarFooter,
28195
+ livePreview,
28196
+ livePreviewSpinner
28147
28197
  }
28148
28198
  ) }) })
28149
28199
  ] }) });
@@ -28745,7 +28795,7 @@ function collectTokenSuggestions(entry, availableTokens = []) {
28745
28795
  const compatiblePaths = new Set(compatible);
28746
28796
  const allowed = availableTokens.length > 0 ? persistedAllowed.filter((path5) => compatiblePaths.has(path5)) : persistedAllowed;
28747
28797
  const paths = availableTokens.length > 0 ? compatible : allowed;
28748
- return { propName, kinds, paths, suggested: [...allowed], allowed };
28798
+ return { propName, paths, suggested: [...allowed], allowed };
28749
28799
  });
28750
28800
  }
28751
28801
  var init_token_suggestions = __esm({
@@ -30696,7 +30746,9 @@ function GenerateReviewStepView({
30696
30746
  initialFocusTarget: pendingEditorFocus && pendingEditorFocus.componentName === selected.key ? pendingEditorFocus.target : { kind: "description" }
30697
30747
  }
30698
30748
  ),
30699
- saveError: reviewEditor.saveError
30749
+ saveError: reviewEditor.saveError,
30750
+ livePreview: livePreviewHook,
30751
+ livePreviewSpinner
30700
30752
  }
30701
30753
  ) : /* @__PURE__ */ jsx48(ReviewNoSelection, {})
30702
30754
  ] }),
@@ -30728,7 +30780,7 @@ function GenerateReviewStepView({
30728
30780
  hidden: dialogOpen
30729
30781
  }
30730
30782
  ),
30731
- !dialogOpen && sidebarFocused && reviewEditor.panelOpen !== "token-review" && /* @__PURE__ */ jsx48(CompactControlBar, { hasGroupRoots, searchActive: searchOpen || searchQuery.length > 0 })
30783
+ !dialogOpen && sidebarFocused && /* @__PURE__ */ jsx48(CompactControlBar, { hasGroupRoots, searchActive: searchOpen || searchQuery.length > 0 })
30732
30784
  ] });
30733
30785
  }
30734
30786
  var HELP_SECTIONS2;
@@ -30810,7 +30862,7 @@ var init_generate_review_step = __esm({
30810
30862
  { keys: "P", label: "Component rationale" },
30811
30863
  { keys: "s", label: "Source code snippet" },
30812
30864
  { keys: "J", label: "Toggle JSON" },
30813
- { keys: "t", label: "Review mapped tokens" }
30865
+ { keys: "t", label: "Token review" }
30814
30866
  ]
30815
30867
  },
30816
30868
  {
@@ -31078,7 +31130,8 @@ function PathPrompt({
31078
31130
  defaultPath,
31079
31131
  onSubmit,
31080
31132
  onCancel,
31081
- label = "Save to"
31133
+ label = "Save to",
31134
+ summary
31082
31135
  }) {
31083
31136
  const [input, setInput] = useState28("");
31084
31137
  const cursorVisible = useBlinkingCursor();
@@ -31112,6 +31165,7 @@ function PathPrompt({
31112
31165
  return /* @__PURE__ */ jsxs42(Box42, { flexDirection: "column", children: [
31113
31166
  /* @__PURE__ */ jsx52(StepHeader, { step: "push" }),
31114
31167
  /* @__PURE__ */ jsxs42(Box42, { flexDirection: "column", gap: 1, paddingX: 2, paddingBottom: 1, children: [
31168
+ summary && /* @__PURE__ */ jsx52(Text44, { color: PALETTE.muted, children: summary }),
31115
31169
  /* @__PURE__ */ jsxs42(Box42, { gap: 1, children: [
31116
31170
  /* @__PURE__ */ jsx52(Text44, { color: PALETTE.accent, children: "?" }),
31117
31171
  /* @__PURE__ */ jsxs42(Text44, { bold: true, children: [
@@ -31153,9 +31207,15 @@ function producedOf(state2) {
31153
31207
  function fileSummaryLabel({ components }) {
31154
31208
  return components ? "components.json" : "components.json (design tokens only)";
31155
31209
  }
31156
- function writtenThings({ components, tokens }) {
31157
- if (components && tokens) return "component types and design tokens";
31158
- return tokens ? "design tokens" : "component types";
31210
+ function counted(count, noun) {
31211
+ if (!count) return `${noun}s`;
31212
+ return `${count} ${noun}${count === 1 ? "" : "s"}`;
31213
+ }
31214
+ function countedThings({ components, tokens }, counts = {}) {
31215
+ const parts = [];
31216
+ if (components || !tokens) parts.push(counted(counts.components, "component type"));
31217
+ if (tokens) parts.push(counted(counts.tokens, "design token"));
31218
+ return parts.join(" and ");
31159
31219
  }
31160
31220
  var init_produced = __esm({
31161
31221
  "packages/experience-design-system-cli/src/tui/import/steps/10-flow/support/produced.ts"() {
@@ -31192,18 +31252,21 @@ var init_use_timed_spinner = __esm({
31192
31252
  import { Box as Box43, Text as Text45 } from "ink";
31193
31253
  import { ProgressBar as ProgressBar2, ThemeProvider as ThemeProvider2 } from "@inkjs/ui";
31194
31254
  import { jsx as jsx54, jsxs as jsxs43 } from "react/jsx-runtime";
31195
- function PushingStep({ progress, produced }) {
31196
- const { elapsed } = useTimedSpinner();
31255
+ function PushingStep({ progress, produced, counts }) {
31256
+ const { spinner, elapsed } = useTimedSpinner();
31197
31257
  const operationId = progress && progress.kind === "queued" ? progress.operationId : null;
31198
31258
  const showGlobal = progress && progress.kind === "progress";
31199
31259
  const showCurrent = progress && progress.kind === "progress" && progress.current ? progress.current : null;
31200
31260
  return /* @__PURE__ */ jsxs43(Box43, { flexDirection: "column", children: [
31201
31261
  /* @__PURE__ */ jsx54(StepHeader, { step: "push" }),
31202
31262
  /* @__PURE__ */ jsxs43(Box43, { flexDirection: "column", gap: 1, paddingX: 2, paddingBottom: 1, children: [
31203
- /* @__PURE__ */ jsxs43(Text45, { children: [
31204
- "Writing ",
31205
- writtenThings(produced),
31206
- " to your Contentful space..."
31263
+ /* @__PURE__ */ jsxs43(Box43, { gap: 1, children: [
31264
+ spinner,
31265
+ /* @__PURE__ */ jsxs43(Text45, { children: [
31266
+ "Writing ",
31267
+ countedThings(produced, counts),
31268
+ " to your Contentful space..."
31269
+ ] })
31207
31270
  ] }),
31208
31271
  operationId && /* @__PURE__ */ jsxs43(Box43, { gap: 1, children: [
31209
31272
  /* @__PURE__ */ jsx54(Text45, { color: PALETTE.muted, children: "Operation:" }),
@@ -31378,20 +31441,12 @@ function diffProperty(name, old, newDef) {
31378
31441
  diffs.push({ key: `${name}-new`, color: PALETTE.success, text: `+ ${name}: ${formatPropDef(newDef)}` });
31379
31442
  return diffs;
31380
31443
  }
31381
- function formatDefault(value) {
31382
- const sys = value?.sys;
31383
- if (sys?.linkType === "Contentful:DesignToken" && typeof sys.urn === "string") {
31384
- const name = sys.urn.split("/designTokens/")[1];
31385
- if (name) return name;
31386
- }
31387
- return JSON.stringify(value);
31388
- }
31389
31444
  function formatOldProp(prop) {
31390
31445
  const parts = [];
31391
31446
  if (prop.type) parts.push(prop.type);
31392
31447
  if (prop.category) parts.push(prop.category);
31393
31448
  parts.push(prop.required ? "required" : "optional");
31394
- if (prop.default !== void 0) parts.push(`default=${formatDefault(prop.default)}`);
31449
+ if (prop.default !== void 0) parts.push(`default=${JSON.stringify(prop.default)}`);
31395
31450
  return parts.join(", ");
31396
31451
  }
31397
31452
  function formatPropDef(def) {
@@ -31400,7 +31455,7 @@ function formatPropDef(def) {
31400
31455
  if (def["$category"]) parts.push(def["$category"]);
31401
31456
  if (def["$required"] === true) parts.push("required");
31402
31457
  else parts.push("optional");
31403
- if (def["$default"] !== void 0) parts.push(`default=${formatDefault(def["$default"])}`);
31458
+ if (def["$default"] !== void 0) parts.push(`default=${JSON.stringify(def["$default"])}`);
31404
31459
  return parts.join(", ");
31405
31460
  }
31406
31461
  var init_preview_diff = __esm({
@@ -31770,6 +31825,8 @@ function FlowScreen({
31770
31825
  onExit
31771
31826
  }) {
31772
31827
  const produced = producedOf(state2);
31828
+ const counts = { components: state2.generatedAcceptedCount, tokens: state2.tokenCount };
31829
+ const things = countedThings(produced, counts);
31773
31830
  const quit = () => onExit(0);
31774
31831
  const content = (() => {
31775
31832
  switch (state2.step) {
@@ -31791,7 +31848,7 @@ function FlowScreen({
31791
31848
  }
31792
31849
  );
31793
31850
  case "previewing":
31794
- return /* @__PURE__ */ jsx56(RunningStep, { step: "push", description: "Computing diff against your Contentful space..." });
31851
+ return /* @__PURE__ */ jsx56(RunningStep, { step: "push", description: `Computing diff for ${things} against your Contentful space...` });
31795
31852
  case "preview-gate":
31796
31853
  if (!state2.serverPreview) return null;
31797
31854
  return /* @__PURE__ */ jsx56(
@@ -31806,11 +31863,12 @@ function FlowScreen({
31806
31863
  }
31807
31864
  );
31808
31865
  case "pushing":
31809
- return /* @__PURE__ */ jsx56(PushingStep, { progress: state2.pushProgress, produced });
31866
+ return /* @__PURE__ */ jsx56(PushingStep, { progress: state2.pushProgress, produced, counts });
31810
31867
  case "path-prompt":
31811
31868
  return /* @__PURE__ */ jsx56(
31812
31869
  PathPrompt,
31813
31870
  {
31871
+ summary: `Saving ${things}${state2.credentialsSkipped ? "" : " and pushing them to your Contentful space"}.`,
31814
31872
  defaultPath: state2.outDir,
31815
31873
  onSubmit: (submitted) => void controller.submitPath(submitted),
31816
31874
  onCancel: quit
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.38.1-dev-build-40e920ee.0",
3
+ "version": "2.38.1-dev-build-db0347a4.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import type { CDFComponentEntry } from '@contentful/experience-design-system-types';
3
3
  import type { CdfReviewEntry } from '../types.js';
4
4
  import type { UseReviewEditorResult } from '../use-review-editor.js';
5
+ import type { UseLivePreviewReturn } from '../use-live-preview.js';
5
6
  import { type ReviewDetailsEditorProps } from './ReviewDetailsEditor.js';
6
7
  type ReviewDetailsEditorConfig = Pick<ReviewDetailsEditorProps, 'componentRationale' | 'reviewMetadata' | 'reviewEditor' | 'width' | 'height' | 'sourceBorderColor' | 'jsonValue' | 'sidebarFocused' | 'fieldEditor'>;
7
8
  export type ReviewComponentPanelProps = ReviewDetailsEditorConfig & {
@@ -9,6 +10,8 @@ export type ReviewComponentPanelProps = ReviewDetailsEditorConfig & {
9
10
  selectedEntry: CDFComponentEntry;
10
11
  saveError: string | null;
11
12
  sidebarFooter?: React.ReactNode;
13
+ livePreview: Pick<UseLivePreviewReturn, 'status' | 'disabled'>;
14
+ livePreviewSpinner: string;
12
15
  };
13
16
  type ReviewFieldEditor = ReviewDetailsEditorProps['fieldEditor'];
14
17
  export declare function buildReviewFieldEditor(reviewEditor: UseReviewEditorResult, selectedJson: string, onExit: () => void, overrides?: Partial<ReviewFieldEditor>): ReviewFieldEditor;
@@ -26,5 +29,5 @@ export declare function ReviewFinalizeError({ message, hidden, }: {
26
29
  message: string | null;
27
30
  hidden: boolean;
28
31
  }): React.ReactElement | null;
29
- export declare function ReviewComponentPanel({ selectedKey, selectedEntry, componentRationale, reviewMetadata, reviewEditor, width, height, sourceBorderColor, jsonValue, sidebarFocused, fieldEditor, saveError, sidebarFooter, }: ReviewComponentPanelProps): React.ReactElement;
32
+ export declare function ReviewComponentPanel({ selectedKey, selectedEntry, componentRationale, reviewMetadata, reviewEditor, width, height, sourceBorderColor, jsonValue, sidebarFocused, fieldEditor, saveError, sidebarFooter, livePreview, livePreviewSpinner, }: ReviewComponentPanelProps): React.ReactElement;
30
33
  export {};
@@ -1,7 +1,6 @@
1
1
  import React from 'react';
2
2
  export type TokenPropSuggestion = {
3
3
  propName: string;
4
- kinds: string[];
5
4
  paths: string[];
6
5
  suggested: string[];
7
6
  allowed: string[];
@@ -12,7 +12,6 @@ export type TokenReviewToken = {
12
12
  };
13
13
  export type TokenPropSuggestion = {
14
14
  propName: string;
15
- kinds: string[];
16
15
  paths: string[];
17
16
  suggested: string[];
18
17
  allowed: string[];
@@ -4,5 +4,7 @@ export type PathPromptProps = {
4
4
  onSubmit: (path: string) => void;
5
5
  onCancel: () => void;
6
6
  label?: string;
7
+ /** What is being saved, shown above the path, such as "Saving 42 design tokens." */
8
+ summary?: string;
7
9
  };
8
- export declare function PathPrompt({ defaultPath, onSubmit, onCancel, label, }: PathPromptProps): React.ReactElement;
10
+ export declare function PathPrompt({ defaultPath, onSubmit, onCancel, label, summary, }: PathPromptProps): React.ReactElement;
@@ -1,9 +1,10 @@
1
1
  import React from 'react';
2
2
  import type { PushProgress } from '../support/push-progress.js';
3
- import { type Produced } from '../support/produced.js';
3
+ import { type Produced, type ProducedCounts } from '../support/produced.js';
4
4
  type PushingStepProps = {
5
5
  progress: PushProgress;
6
6
  produced: Produced;
7
+ counts: ProducedCounts;
7
8
  };
8
- export declare function PushingStep({ progress, produced }: PushingStepProps): React.ReactElement;
9
+ export declare function PushingStep({ progress, produced, counts }: PushingStepProps): React.ReactElement;
9
10
  export {};
@@ -11,5 +11,15 @@ export declare function producedOf(state: Pick<FlowState, 'extractSessionId' | '
11
11
  * holds just the tokens, and calling it a components file would mislead.
12
12
  */
13
13
  export declare function fileSummaryLabel({ components }: Produced): string;
14
+ /** How many of each thing a run writes. A missing or zero count is left out of the wording, never shown as "0". */
15
+ export interface ProducedCounts {
16
+ components?: number;
17
+ tokens?: number;
18
+ }
19
+ /**
20
+ * "12 component types and 42 design tokens", "42 design tokens", or "component types": the things this run writes, with
21
+ * how many of each when known.
22
+ */
23
+ export declare function countedThings({ components, tokens }: Produced, counts?: ProducedCounts): string;
14
24
  /** "component types and design tokens", "design tokens", or "component types": the things this run writes. */
15
- export declare function writtenThings({ components, tokens }: Produced): string;
25
+ export declare function writtenThings(produced: Produced): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.38.1-dev-build-40e920ee.0",
3
+ "version": "2.38.1-dev-build-db0347a4.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -45,8 +45,8 @@
45
45
  "ts-morph": "^27.0.2",
46
46
  "typescript": "^5.9.3",
47
47
  "zod": "^4.6.5",
48
- "@contentful/experience-design-system-backend-pipeline": "2.38.1-dev-build-40e920ee.0",
49
- "@contentful/experience-design-system-types": "2.38.1-dev-build-40e920ee.0"
48
+ "@contentful/experience-design-system-types": "2.38.1-dev-build-db0347a4.0",
49
+ "@contentful/experience-design-system-backend-pipeline": "2.38.1-dev-build-db0347a4.0"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@tsconfig/node24": "^24.0.4",