@proveanything/smartlinks-utils-ui 0.10.3 → 0.10.5

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.
@@ -336,6 +336,10 @@ interface RecordsAdminI18n {
336
336
  previewAs: string;
337
337
  previewAsDefault: string;
338
338
  confirmDelete: string;
339
+ /** Confirm dialog title shown when the row trash is clicked in the item list. */
340
+ deleteConfirmTitle: string;
341
+ /** Confirm dialog body. `{name}` is replaced with the record's friendly label. */
342
+ deleteConfirmBody: string;
339
343
  unsavedBadge: string;
340
344
  unsavedPromptTitle: string;
341
345
  unsavedPromptBody: string;
@@ -2454,6 +2458,15 @@ interface Props<T> {
2454
2458
  contextKind?: string;
2455
2459
  contextSummary?: string | null;
2456
2460
  onSelect: (itemId: string) => void;
2461
+ /**
2462
+ * Optional sticky "+ New {noun}" affordance pinned to the bottom of the
2463
+ * rail. When supplied the rail renders a footer button that calls this
2464
+ * callback. Mirrors the toolbar `+ New` in the list view so admins can
2465
+ * add another record without first navigating back to the list.
2466
+ */
2467
+ onCreate?: () => void;
2468
+ /** Noun used in the "+ New {noun}" footer label. */
2469
+ itemNoun?: string;
2457
2470
  /**
2458
2471
  * Set of keys (recordIds + scope refs) currently dirty in the shell-level
2459
2472
  * draft store. Used to paint a per-row pip on items the user has edited
@@ -2463,9 +2476,9 @@ interface Props<T> {
2463
2476
  dirtyKeys?: ReadonlySet<string>;
2464
2477
  /** Subset of `dirtyKeys` whose last save attempt failed. */
2465
2478
  errorKeys?: ReadonlySet<string>;
2466
- i18n: Pick<RecordsAdminI18n, 'backToScopes' | 'siblingsHeading' | 'noItemsTitle' | 'noItemsBody' | 'backToList'>;
2479
+ i18n: Pick<RecordsAdminI18n, 'backToScopes' | 'siblingsHeading' | 'noItemsTitle' | 'noItemsBody' | 'backToList' | 'newItem'>;
2467
2480
  }
2468
- declare function SiblingRail<T>({ items, selectedItemId, isLoading, error, onBack, onSelect, contextKind, contextSummary, dirtyKeys, errorKeys, i18n, }: Props<T>): react_jsx_runtime.JSX.Element;
2481
+ declare function SiblingRail<T>({ items, selectedItemId, isLoading, error, onBack, onSelect, contextKind, contextSummary, onCreate, itemNoun, dirtyKeys, errorKeys, i18n, }: Props<T>): react_jsx_runtime.JSX.Element;
2469
2482
 
2470
2483
  interface ClipboardEntry<T = unknown> {
2471
2484
  value: T;
@@ -92,6 +92,8 @@ var DEFAULT_I18N = {
92
92
  previewAs: "Preview as",
93
93
  previewAsDefault: "Same as edited",
94
94
  confirmDelete: "Confirm delete",
95
+ deleteConfirmTitle: "Delete this record?",
96
+ deleteConfirmBody: "Are you sure you want to delete \u201C{name}\u201D? This cannot be undone.",
95
97
  unsavedBadge: "Unsaved",
96
98
  unsavedPromptTitle: "Unsaved changes",
97
99
  unsavedPromptBody: "You have unsaved changes. What would you like to do?",
@@ -2949,9 +2951,9 @@ function useEditorBridge(args) {
2949
2951
  const next = session?.status ?? null;
2950
2952
  prevStatusRef.current = next;
2951
2953
  if (next === "saved" && prev !== "saved") {
2952
- onSaved?.();
2954
+ onSaved?.(session?.recordId);
2953
2955
  }
2954
- }, [session?.status]);
2956
+ }, [session?.status, session?.recordId]);
2955
2957
  const remove = useMemo(() => async () => {
2956
2958
  if (!session) return;
2957
2959
  await session.remove();
@@ -3077,7 +3079,7 @@ function useShellEditorTarget(args) {
3077
3079
  facetRule: resolved.facetRule
3078
3080
  },
3079
3081
  defaultData,
3080
- onSaved: () => onSaved(resolved.source !== "self"),
3082
+ onSaved: (recordId) => onSaved(resolved.source !== "self", recordId),
3081
3083
  onDeleted
3082
3084
  });
3083
3085
  return { editorTargetSpec, editorCtx };
@@ -5830,6 +5832,17 @@ function ItemListView({
5830
5832
  i18n
5831
5833
  }) {
5832
5834
  const newLabel = i18n.newItem.includes("{noun}") ? i18n.newItem.replace("{noun}", itemNoun) : i18n.newItem;
5835
+ const [pendingDeleteId, setPendingDeleteId] = useState(null);
5836
+ const pendingRecord = useMemo(
5837
+ () => pendingDeleteId ? items.find((it) => (it.itemId ?? "") === pendingDeleteId) ?? null : null,
5838
+ [pendingDeleteId, items]
5839
+ );
5840
+ const guardedCtx = useMemo(() => ({
5841
+ ...ctx,
5842
+ onDelete: (id) => setPendingDeleteId(id)
5843
+ }), [ctx]);
5844
+ const confirmName = pendingRecord?.label ?? itemNoun;
5845
+ const confirmBody = i18n.deleteConfirmBody.includes("{name}") ? i18n.deleteConfirmBody.replace("{name}", confirmName) : i18n.deleteConfirmBody;
5833
5846
  const toolbar = /* @__PURE__ */ jsxs("div", { className: "ra-item-toolbar", children: [
5834
5847
  /* @__PURE__ */ jsxs("div", { className: "ra-item-toolbar-title", children: [
5835
5848
  /* @__PURE__ */ jsx("h2", { className: "ra-display", style: { fontSize: "0.95rem", margin: 0 }, children: i18n.itemListTitle }),
@@ -5887,16 +5900,16 @@ function ItemListView({
5887
5900
  }
5888
5901
  );
5889
5902
  } else if (renderItemList) {
5890
- body = renderItemList(items, ctx);
5903
+ body = renderItemList(items, guardedCtx);
5891
5904
  } else if (view === "table") {
5892
5905
  body = /* @__PURE__ */ jsx(
5893
5906
  DefaultItemTable,
5894
5907
  {
5895
5908
  items,
5896
5909
  columns: itemColumns,
5897
- selectedId: ctx.selectedId,
5898
- onOpen: ctx.onOpen,
5899
- onDelete: ctx.onDelete,
5910
+ selectedId: guardedCtx.selectedId,
5911
+ onOpen: guardedCtx.onOpen,
5912
+ onDelete: guardedCtx.onDelete,
5900
5913
  rowActions,
5901
5914
  rowClipboard,
5902
5915
  i18n
@@ -5908,8 +5921,8 @@ function ItemListView({
5908
5921
  {
5909
5922
  items,
5910
5923
  variant: view,
5911
- selectedId: ctx.selectedId,
5912
- ctx,
5924
+ selectedId: guardedCtx.selectedId,
5925
+ ctx: guardedCtx,
5913
5926
  renderCard: renderItemCard,
5914
5927
  cardSize,
5915
5928
  rowActions,
@@ -5941,7 +5954,23 @@ function ItemListView({
5941
5954
  ]
5942
5955
  }
5943
5956
  ) : null,
5944
- /* @__PURE__ */ jsx("div", { className: "ra-item-list-body", children: body })
5957
+ /* @__PURE__ */ jsx("div", { className: "ra-item-list-body", children: body }),
5958
+ /* @__PURE__ */ jsx(
5959
+ ConfirmDialog,
5960
+ {
5961
+ open: pendingDeleteId !== null,
5962
+ title: i18n.deleteConfirmTitle,
5963
+ body: confirmBody,
5964
+ saveLabel: "",
5965
+ discardLabel: i18n.delete,
5966
+ cancelLabel: i18n.pasteConfirmCancel,
5967
+ onChoice: (choice) => {
5968
+ const id = pendingDeleteId;
5969
+ setPendingDeleteId(null);
5970
+ if (choice === "discard" && id !== null) ctx.onDelete(id);
5971
+ }
5972
+ }
5973
+ )
5945
5974
  ] });
5946
5975
  }
5947
5976
  var EditorItemNav = ({
@@ -6010,11 +6039,14 @@ function SiblingRail({
6010
6039
  onSelect,
6011
6040
  contextKind,
6012
6041
  contextSummary,
6042
+ onCreate,
6043
+ itemNoun,
6013
6044
  dirtyKeys,
6014
6045
  errorKeys,
6015
6046
  i18n
6016
6047
  }) {
6017
6048
  const ruleLabelLookup = useRuleLabelLookup();
6049
+ const newLabel = i18n.newItem.includes("{noun}") ? i18n.newItem.replace("{noun}", itemNoun ?? "item") : i18n.newItem;
6018
6050
  return /* @__PURE__ */ jsxs("div", { className: "ra-sibling-rail", children: [
6019
6051
  (onBack || contextKind) && /* @__PURE__ */ jsxs("div", { className: "ra-sibling-context", children: [
6020
6052
  onBack && /* @__PURE__ */ jsx(
@@ -6090,7 +6122,20 @@ function SiblingRail({
6090
6122
  }
6091
6123
  ) }, key);
6092
6124
  }) })
6093
- ] })
6125
+ ] }),
6126
+ onCreate && /* @__PURE__ */ jsx("div", { className: "ra-sibling-footer", children: /* @__PURE__ */ jsxs(
6127
+ "button",
6128
+ {
6129
+ type: "button",
6130
+ onClick: onCreate,
6131
+ className: "ra-sibling-create",
6132
+ title: newLabel,
6133
+ children: [
6134
+ /* @__PURE__ */ jsx(Plus, { className: "w-3.5 h-3.5", "aria-hidden": "true" }),
6135
+ /* @__PURE__ */ jsx("span", { children: newLabel })
6136
+ ]
6137
+ }
6138
+ ) })
6094
6139
  ] });
6095
6140
  }
6096
6141
  var TONE_ICON = {
@@ -7740,7 +7785,7 @@ function RecordsAdminShellInner(props) {
7740
7785
  },
7741
7786
  defaultData,
7742
7787
  deriveDraftLabel,
7743
- onSaved: (isCreate) => {
7788
+ onSaved: (isCreate, savedRecordId) => {
7744
7789
  onTelemetry?.({ type: "record.save", recordType, ref: editingTargetScope?.raw ?? "", isCreate });
7745
7790
  if (ruleWizardStep !== null) {
7746
7791
  setRuleWizardStep(null);
@@ -7751,6 +7796,9 @@ function RecordsAdminShellInner(props) {
7751
7796
  setSelectedRecordId(null);
7752
7797
  setDraftKind(null);
7753
7798
  }
7799
+ if (isCreate && isCollection && savedRecordId && isDraftId3(selectedItemId)) {
7800
+ setSelectedItemId(savedRecordId);
7801
+ }
7754
7802
  refetchAll();
7755
7803
  },
7756
7804
  onDeleted: () => {
@@ -8565,6 +8613,8 @@ function RecordsAdminShellInner(props) {
8565
8613
  error: collectionItems.error,
8566
8614
  onBack: onItemBack,
8567
8615
  onSelect: onItemOpen,
8616
+ onCreate: onItemCreate,
8617
+ itemNoun: itemNounLabel,
8568
8618
  dirtyKeys,
8569
8619
  errorKeys,
8570
8620
  contextKind: activeScope === "rule" ? "Rule" : activeScope === "product" ? "Product" : activeScope === "collection" ? "Global" : activeScope === "all" ? "All records" : activeScope === "variant" ? "Variant" : activeScope === "batch" ? "Batch" : activeScope === "facet" ? "Facet" : void 0,